<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Hibernate笔记 | 净土</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="Hibernate">
<meta property="og:type" content="article">
<meta property="og:title" content="Hibernate笔记">
<meta property="og:url" content="http://howiefh.github.io/2015/03/05/hibernate-note/index.html">
<meta property="og:site_name" content="净土">
<meta property="og:description" content="Hibernate">
<meta property="og:image" content="http://fh-1.qiniudn.com/PO_lifecycle.jpg">
<meta property="og:image" content="http://fh-1.qiniudn.com/hibernate_simple_struct.gif">
<meta property="og:image" content="http://fh-1.qiniudn.com/hibernate_struct.gif">
<meta property="og:image" content="http://fh-1.qiniudn.com/PO_lifecycle.jpg">
<meta property="og:updated_time" content="2015-03-13T02:19:24.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Hibernate笔记">
<meta name="twitter:description" content="Hibernate">
  
    <link rel="alternative" href="/atom.xml" title="净土" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.ico">
  
  <link href="http://fonts.useso.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-40492061-1', 'auto');
ga('send', 'pageview');

</script>


  
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?56d2899c5e919fbf4a7b00de5d1c31dd";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>


</head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">净土</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/" id="subtitle">乐不在外而在心，心以为乐，则是境皆乐；心以为苦，则无境不苦。</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-github-link" class="nav-icon" href="https://github.com/howiefh" title="Github" target="_blank"></a>
        
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed" target="_blank"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://howiefh.github.io"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-hibernate-note" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    
<a href="/2015/03/05/hibernate-note/" class="article-date">
  <time datetime="2015-03-05T14:49:08.000Z" itemprop="datePublished">2015-03-05</time>
</a>


    
  <div class="article-category">
    <a class="article-category-link" href="/categories/JavaEE/">JavaEE</a>►<a class="article-category-link" href="/categories/JavaEE/Hibernate/">Hibernate</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Hibernate笔记
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
		
		<div id="toc" class="toc-article">
			<h2 class="toc-title"><span>Contents</span></h2>
		
			<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#对象/关系数据库映射(ORM)"><span class="toc-number">1.</span> <span class="toc-text">对象/关系数据库映射(ORM)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#ORM基本映射方式"><span class="toc-number">1.1.</span> <span class="toc-text">ORM基本映射方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#流行的ORM框架"><span class="toc-number">1.2.</span> <span class="toc-text">流行的ORM框架</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Hibernate入门"><span class="toc-number">2.</span> <span class="toc-text">Hibernate入门</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate下载和安装"><span class="toc-number">2.1.</span> <span class="toc-text">Hibernate下载和安装</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate的数据库操作"><span class="toc-number">2.2.</span> <span class="toc-text">Hibernate的数据库操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#在Eclipse中使用Hibernate"><span class="toc-number">2.3.</span> <span class="toc-text">在Eclipse中使用Hibernate</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Hibernate体系结构"><span class="toc-number">3.</span> <span class="toc-text">Hibernate体系结构</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#深入Hibernate的配置文件"><span class="toc-number">4.</span> <span class="toc-text">深入Hibernate的配置文件</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#JDBC连接属性"><span class="toc-number">4.1.</span> <span class="toc-text">JDBC连接属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数据库方言"><span class="toc-number">4.2.</span> <span class="toc-text">数据库方言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JNDI数据源的连接属性"><span class="toc-number">4.3.</span> <span class="toc-text">JNDI数据源的连接属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate事务属性"><span class="toc-number">4.4.</span> <span class="toc-text">Hibernate事务属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#二级缓存相关属性"><span class="toc-number">4.5.</span> <span class="toc-text">二级缓存相关属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#外连接抓取属性"><span class="toc-number">4.6.</span> <span class="toc-text">外连接抓取属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#其他常用的配置属性"><span class="toc-number">4.7.</span> <span class="toc-text">其他常用的配置属性</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#深入理解持久化对象"><span class="toc-number">5.</span> <span class="toc-text">深入理解持久化对象</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#持久化类的要求"><span class="toc-number">5.1.</span> <span class="toc-text">持久化类的要求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#持久化对象的状态"><span class="toc-number">5.2.</span> <span class="toc-text">持久化对象的状态</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#改变持久化对象状态的方法"><span class="toc-number">5.3.</span> <span class="toc-text">改变持久化对象状态的方法</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#映射"><span class="toc-number">6.</span> <span class="toc-text">映射</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#映射实体"><span class="toc-number">6.1.</span> <span class="toc-text">映射实体</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#映射属性"><span class="toc-number">6.2.</span> <span class="toc-text">映射属性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#非主属性"><span class="toc-number">6.2.1.</span> <span class="toc-text">非主属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#主属性"><span class="toc-number">6.2.2.</span> <span class="toc-text">主属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#乐观锁和不用持久化"><span class="toc-number">6.2.3.</span> <span class="toc-text">乐观锁和不用持久化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#复合属性—组件映射"><span class="toc-number">6.2.4.</span> <span class="toc-text">复合属性—组件映射</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#复合属性—复合主键"><span class="toc-number">6.2.5.</span> <span class="toc-text">复合属性—复合主键</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#集合映射"><span class="toc-number">6.3.</span> <span class="toc-text">集合映射</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#映射继承关系"><span class="toc-number">6.4.</span> <span class="toc-text">映射继承关系</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#每个类一张表"><span class="toc-number">6.4.1.</span> <span class="toc-text">每个类一张表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#每个类层次结构一张表"><span class="toc-number">6.4.2.</span> <span class="toc-text">每个类层次结构一张表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#连接的子类"><span class="toc-number">6.4.3.</span> <span class="toc-text">连接的子类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#从父类继承的属性"><span class="toc-number">6.4.4.</span> <span class="toc-text">从父类继承的属性</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#关联关系映射"><span class="toc-number">6.5.</span> <span class="toc-text">关联关系映射</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—简介"><span class="toc-number">6.5.1.</span> <span class="toc-text">关联关系映射—简介</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—数据库降级使用"><span class="toc-number">6.5.2.</span> <span class="toc-text">关联关系映射—数据库降级使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:1—共享主键"><span class="toc-number">6.5.3.</span> <span class="toc-text">关联关系映射—1:1—共享主键</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:M—外键"><span class="toc-number">6.5.4.</span> <span class="toc-text">关联关系映射—1:M—外键</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—M:N—联接表"><span class="toc-number">6.5.5.</span> <span class="toc-text">关联关系映射—M:N—联接表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:M—联接表"><span class="toc-number">6.5.6.</span> <span class="toc-text">关联关系映射—1:M—联接表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:1—联接表"><span class="toc-number">6.5.7.</span> <span class="toc-text">关联关系映射—1:1—联接表</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#二级缓存"><span class="toc-number">6.6.</span> <span class="toc-text">二级缓存</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#批量处理"><span class="toc-number">7.</span> <span class="toc-text">批量处理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#使用HQL查询"><span class="toc-number">8.</span> <span class="toc-text">使用HQL查询</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#from子句"><span class="toc-number">8.1.</span> <span class="toc-text">from子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#关联和连接"><span class="toc-number">8.2.</span> <span class="toc-text">关联和连接</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#select子句"><span class="toc-number">8.3.</span> <span class="toc-text">select子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HQL查询的聚集函数"><span class="toc-number">8.4.</span> <span class="toc-text">HQL查询的聚集函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#多态查询"><span class="toc-number">8.5.</span> <span class="toc-text">多态查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HQL查询的where子句"><span class="toc-number">8.6.</span> <span class="toc-text">HQL查询的where子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#表达式"><span class="toc-number">8.7.</span> <span class="toc-text">表达式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#order_by子句"><span class="toc-number">8.8.</span> <span class="toc-text">order by子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#group_by子句"><span class="toc-number">8.9.</span> <span class="toc-text">group by子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#子查询"><span class="toc-number">8.10.</span> <span class="toc-text">子查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#命名查询"><span class="toc-number">8.11.</span> <span class="toc-text">命名查询</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#条件查询"><span class="toc-number">9.</span> <span class="toc-text">条件查询</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#关联和动态关联"><span class="toc-number">9.1.</span> <span class="toc-text">关联和动态关联</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#投影(Projections)、聚合（aggregation）和分组（grouping）"><span class="toc-number">9.2.</span> <span class="toc-text">投影(Projections)、聚合（aggregation）和分组（grouping）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#离线(detached)查询和子查询"><span class="toc-number">9.3.</span> <span class="toc-text">离线(detached)查询和子查询</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SQL查询"><span class="toc-number">10.</span> <span class="toc-text">SQL查询</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#标量查询"><span class="toc-number">10.1.</span> <span class="toc-text">标量查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#实体查询"><span class="toc-number">10.2.</span> <span class="toc-text">实体查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#处理关联和继承"><span class="toc-number">10.3.</span> <span class="toc-text">处理关联和继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#命名SQL查询"><span class="toc-number">10.4.</span> <span class="toc-text">命名SQL查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#调用存储过程"><span class="toc-number">10.5.</span> <span class="toc-text">调用存储过程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#定制SQL"><span class="toc-number">10.6.</span> <span class="toc-text">定制SQL</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#数据过滤"><span class="toc-number">11.</span> <span class="toc-text">数据过滤</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#事物控制"><span class="toc-number">12.</span> <span class="toc-text">事物控制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#事务的概念"><span class="toc-number">12.1.</span> <span class="toc-text">事务的概念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Session与事务"><span class="toc-number">12.2.</span> <span class="toc-text">Session与事务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#上下文相关的会话"><span class="toc-number">12.3.</span> <span class="toc-text">上下文相关的会话</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二级缓存和查询缓存"><span class="toc-number">13.</span> <span class="toc-text">二级缓存和查询缓存</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#开启二级缓存"><span class="toc-number">13.1.</span> <span class="toc-text">开启二级缓存</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#管理缓存和统计缓存"><span class="toc-number">13.2.</span> <span class="toc-text">管理缓存和统计缓存</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用查询缓存"><span class="toc-number">13.3.</span> <span class="toc-text">使用查询缓存</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#事件机制"><span class="toc-number">14.</span> <span class="toc-text">事件机制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#拦截器"><span class="toc-number">14.1.</span> <span class="toc-text">拦截器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#事件系统"><span class="toc-number">14.2.</span> <span class="toc-text">事件系统</span></a></li></ol></li></ol>
		
		</div>
		
        <h2 id="对象/关系数据库映射(ORM)">对象/关系数据库映射(ORM)</h2><p>ORM全称是Object/Relation Mapping，对象/关系数据库映射。ORM可理解成一种规范，它概述了这类框架的基本特征：完成面向对象的编程语言到关系数据库的映射。</p>
<a id="more"></a>
<h3 id="ORM基本映射方式">ORM基本映射方式</h3><ul>
<li>数据表映射类：持久化类被映射到一个数据表。</li>
<li>数据表的行映射对象：持久化类会生成很多实例，每个实例就对应数据表中的一行记录。</li>
<li>数据表的列映射对象的属性。</li>
</ul>
<h3 id="流行的ORM框架">流行的ORM框架</h3><ul>
<li>JPA:JPA只是一种ORM规范，并不是ORM产品。提供接口，而不是实现。所以如果面向JPA编程，那么程序即可在各种ORM框架之间自由切换。</li>
<li>Hibernate</li>
<li>iBATIS</li>
<li>TopLink</li>
</ul>
<h2 id="Hibernate入门">Hibernate入门</h2><h3 id="Hibernate下载和安装">Hibernate下载和安装</h3><p>从 <a href="http://hibernate.org" target="_blank" rel="external">http://hibernate.org</a> 进行下载。<br>将hibernate[version].jar和lib路径下的required、bytecode、jpa子目录下所有JAR包添加到应用的类加载路径中。Hibernate底层依然基于JDBC，所以JDBC对应的驱动也要添加到类加载路径中。</p>
<h3 id="Hibernate的数据库操作">Hibernate的数据库操作</h3><p>ORM框架中非常重要的媒介：PO(Persistent Object，持久化对象)。持久化对象的作用是完成持久化操作，简单说，通过该对象可对数据执行增删改查操作—以面向对象的方式操作数据库。</p>
<p>Hibernate使用POJO(普通、传统Java对象)作为PO</p>
<p>News.java</p>
<figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> class News&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">Integer</span> id;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">String</span> title;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">String</span> content;</span><br><span class="line">    <span class="comment">//setter 和 getter方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>News.hbm.xml:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="doctype">&lt;!DOCTYPE hibernate-mapping PUBLIC</span><br><span class="line">"-//Hibernate/Hibernate Mapping DTD 3.0//EN"</span><br><span class="line">"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">hibernate-mapping</span> <span class="attribute">package</span>=<span class="value">"pojo"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 每个class元素对应一个持久化对象 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">class</span> <span class="attribute">name</span>=<span class="value">"News"</span> <span class="attribute">table</span>=<span class="value">"news_table"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- id元素定义持久化类的标识属性 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">id</span> <span class="attribute">name</span>=<span class="value">"id"</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定主键生成策略 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">generator</span> <span class="attribute">class</span>=<span class="value">"identity"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"title"</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"content"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">class</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">hibernate-mapping</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>Hibernate配置文件hibernate.cfg.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="doctype">&lt;!DOCTYPE hibernate-configuration PUBLIC</span><br><span class="line">"-//Hibernate/Hibernate Configuration DTD 3.0//EN"</span><br><span class="line">"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">hibernate-configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">session-factory</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接数据库所用的驱动 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"connection.driver_class"</span>&gt;</span>com.mysql.jdbc.Driver<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接数据库的url，hibernate连接的数据库名 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"connection.url"</span>&gt;</span>jdbc:mysql://192.168.0.121/dbname<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接数据库的用户名 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"connection.username"</span>&gt;</span>root<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接数据库的密码 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"connection.password"</span>&gt;</span><span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接池最大连接数 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.c3p0.max_size"</span>&gt;</span>20<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接池最小连接数 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.c3p0.min_size"</span>&gt;</span>1<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定连接池里最大缓存多少个Statement对象 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.c3p0.max_statements"</span>&gt;</span>100<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.c3p0.idle_test_period"</span>&gt;</span>3000<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.c3p0.acquire_increment"</span>&gt;</span>2<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.c3p0.validate"</span>&gt;</span>true<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 指定数据库方言 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"dialect"</span>&gt;</span>org.hibernate.dialect.MySQLInnoDBDialect<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 根据需要自动创建数据表 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hbm2ddl.auto"</span>&gt;</span>update<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 映射文件 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">mapping</span> <span class="attribute">class</span>=<span class="value">"pojo.News"</span>/&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="title">ssion-factory</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">hibernate-configuration</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>Hibernate并不推荐DriverManager来连接数据库，而是推荐使用数据源来管理数据库连接，这样能保证更好的性能。Hibernate推荐使用C2P0数据源。</p>
<p>数据源是一种提高数据库连接性能的常规手段，数据源会负责维持一个数据库连接池，当程序创建数据源实例时，系统会一次性地创建多个数据库连接，并把这些数据库连接保存在连接池中，当程序需要进行数据库访问时，无须重新获得数据库连接，而是从连接池中取出一个空闲的数据库连接。当程序使用数据库连接访问数据结束后，无须关闭数据库连接，而是将数据库连接归还给连接池即可，通过这种方式可以避免频繁地获取数据库连接、关闭数据库连接所导致的性能下降。</p>
<p>完成消息的插入操作</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实例化Configuration, configure方法加载hibernate.cfg.xml文件</span></span><br><span class="line">Configuration conf = new Configuration<span class="params">()</span>.configure<span class="params">()</span>;</span><br><span class="line"><span class="comment">//以Configuration创建SessionFactory</span></span><br><span class="line">SessionFactory sf = conf.buildSessionFactory<span class="params">()</span>;</span><br><span class="line"><span class="comment">//创建Session</span></span><br><span class="line">Session sess = sf.openSession<span class="params">()</span>;</span><br><span class="line"><span class="comment">//开始事务</span></span><br><span class="line">Transaction tx = sess.beginTransaction<span class="params">()</span>;</span><br><span class="line"><span class="comment">//创建消息实例</span></span><br><span class="line">News n = new News<span class="params">()</span>;</span><br><span class="line">n.setTitle<span class="params">(<span class="string">""</span>)</span>;</span><br><span class="line">n.setContent<span class="params">(<span class="string">""</span>)</span>;</span><br><span class="line"><span class="comment">//保存消息</span></span><br><span class="line">sess.save<span class="params">(n)</span>;</span><br><span class="line"><span class="comment">//提交事务</span></span><br><span class="line">tx.commit<span class="params">()</span>;</span><br><span class="line"><span class="comment">//关闭session</span></span><br><span class="line">sess.close<span class="params">()</span>;</span><br><span class="line">sf.close<span class="params">()</span>;</span><br></pre></td></tr></table></figure>
<p>PO只有在Session的管理下才可完成数据库访问。为了使用Hibernate进行持久化操作，通常有如下操作步骤。</p>
<ul>
<li>开发持久化类，由POJO加映射文件组成</li>
<li>获取Configuration</li>
<li>获取SessionFactory</li>
<li>获取Session，打开事务 </li>
<li>用面向对象的方式操作数据库</li>
<li>关闭事务，关闭Session</li>
</ul>
<p>随PO与Session的关联关系，PO有如下三种状态    </p>
<ul>
<li>瞬态：PO从未与Session关联</li>
<li>持久化：PO实例与Session关联起来，且该实例对应到数据库记录。</li>
<li>脱管：PO实例曾经与Session关联，但因为Session关闭等原因，PO实例脱离Session的管理。</li>
</ul>
<p><img src="http://fh-1.qiniudn.com/PO_lifecycle.jpg" alt="持久化对象的生命周期"></p>
<p>对PO的操作必须在Session管理下才能同步到数据库。Session由SessionFactory工厂产生，SessionFactory是数据库编译后的内存镜像，通常一个应用对应一个SessionFactory对象。SessionFactory对象由Configuration对象产生，Configuration对象负责加载Hibernate配置文件。</p>
<h3 id="在Eclipse中使用Hibernate">在Eclipse中使用Hibernate</h3><p>Hibernate官方提供HibernateTools插件。</p>
<p>hibernate.cfg.xml文件通常在src目录下。</p>
<p>如果希望显示sql语句，自动建表可以在配置文件hibernate.cfg.xml中添加hibernate.show_sql、hibernate.format_sql和hibernate.hbm2ddl.auto</p>
<h2 id="Hibernate体系结构">Hibernate体系结构</h2><p><img src="http://fh-1.qiniudn.com/hibernate_simple_struct.gif" alt="Hibernate简要体系结构"><br><img src="http://fh-1.qiniudn.com/hibernate_struct.gif" alt="Hibernate全面解决方案体系结构"></p>
<ul>
<li>SessionFactory：这是Hibernate的关键对象，它是单个数据库映射关系经过编译后的内存镜像，它也是线程安全的。它是生成Session的工厂，本身要应用到ConnectionProvider，该对象可以在进程和集群的级别上，为那些事务之间可以重用的数据提供可选的二级缓存。</li>
<li>Session：它是应用程序和持久存储层之间交互操作的一个单线程对象。它也是Hibernate持久化操作的关键对象，所有的持久化对象必须在Session的管理下才能够进行持久化操作。此对象的生存周期很短，其隐藏了JDBC连接，也是Transaction 的工厂。Session对象有一个一级缓存，现实执行Flush之前，所有的持久化操作的数据都在缓存中Session对象处。</li>
<li>持久化对象：系统创建的POJO实例一旦与特定Session关联，并对应数据表的指定记录，那该对象就处于持久化状态，这一系列的对象都被称为持久化对象。程序中对持久化对象的修改，都将自动转换为持久层的修改。持久化对象完全可以是普通的Java Beans/POJO，唯一的特殊性是它们正与Session关联着。</li>
<li>瞬态对象和脱管对象：系统进行new关键字进行创建的Java 实例，没有Session 相关联，此时处于瞬态。瞬态实例可能是在被应用程序实例化后，尚未进行持久化的对象。如果一个曾经持久化过的实例，但因为Session的关闭而转换为脱管状态。</li>
<li>事务(Transaction)：代表一次原子操作，它具有数据库事务的概念。但它通过抽象，将应用程序从底层的具体的JDBC、JTA和CORBA事务中隔离开。在某些情况下，一个Session 之内可能包含多个Transaction对象。虽然事务操作是可选的，但是所有的持久化操作都应该在事务管理下进行，即使是只读操作。</li>
<li>连接提供者(ConnectionProvider)：它是生成JDBC的连接的工厂，同时具备连接池的作用。他通过抽象将底层的DataSource和DriverManager隔离开。这个对象无需应用程序直接访问，仅在应用程序需要扩展时使用。</li>
<li>事务工厂(TransactionFactory)：他是生成Transaction对象实例的工厂。该对象也无需应用程序的直接访问。</li>
</ul>
<h2 id="深入Hibernate的配置文件">深入Hibernate的配置文件</h2><ol>
<li><p>使用hibernate.properties作为配置文件</p>
<p> 需要通过addResource方法添加映射文件<code>new Configuration().addResource(&quot;News.hbm.xml&quot;)</code>。也可以通过addClass()方法添加持久化类<code>new Configuration().addClass(lee.Nuews.class)</code>此时映射文件应该放在类文件相同的包路径下。Hibernate自己会去搜索。</p>
</li>
<li><p>使用hibernate.cfg.xml作为配置文件</p>
<p> hibernate.cfg.xml文件中已经添加了Hibernate映射文件。<code>new Configuration().configure()</code></p>
</li>
<li><p>不用配置文件创建Configuration实例</p>
<p> 使用下面三个方法</p>
 <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Configuration <span class="function"><span class="title">addResource</span><span class="params">(String resourceName)</span></span></span><br><span class="line">Configuration <span class="function"><span class="title">setProperties</span><span class="params">(Properties properties)</span></span></span><br><span class="line">Configuration <span class="function"><span class="title">setProperty</span><span class="params">(String propertyName, String value)</span></span></span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="JDBC连接属性">JDBC连接属性</h3><p>所有Hibernate属性的名字和语义都在org.hibernate.cfg.Environment中定义。</p>
<ul>
<li>hibernate.connection.driver_class：指定连接数据库所用的驱动。</li>
<li>hibernate.connection.url：指定连接数据库的url，hibernate连接的数据库名。</li>
<li>hibernate.connection.username：该属性是可选的。</li>
<li>hibernate.connection.passowrd：该属性是可选的。</li>
<li>hibernate.connection.pool_size：设置Hibernate数据库连接池的最大并发连接数。</li>
<li>hibernate.dialect：设置连接数据库所使用的方言。</li>
</ul>
<p>Hibernate自带的连接池仅有测试价值，实际项目中使用C3P0或Proxool连接池。</p>
<h3 id="数据库方言">数据库方言</h3><table>
<thead>
<tr>
<th>关系型数据库</th>
<th>方言</th>
</tr>
</thead>
<tbody>
<tr>
<td>DB2</td>
<td>org.hibernate.dialect.DB2Dialect</td>
</tr>
<tr>
<td>DB2 AS/400</td>
<td>org.hibernate.dialect.DB2400Dialect</td>
</tr>
<tr>
<td>DB2 OS390</td>
<td>org.hibernate.dialect.DB2390Dialect</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>org.hibernate.dialect.PostgreSQLDialect</td>
</tr>
<tr>
<td>MySQL</td>
<td>org.hibernate.dialect.MySQLDialect</td>
</tr>
<tr>
<td>MySQL with InnoDB</td>
<td>org.hibernate.dialect.MySQLInnoDBDialect</td>
</tr>
<tr>
<td>MySQL with MyISAM</td>
<td>org.hibernate.dialect.MySQLMyISAMDialect</td>
</tr>
<tr>
<td>Oracle (any version)</td>
<td>org.hibernate.dialect.OracleDialect</td>
</tr>
<tr>
<td>Oracle 9i</td>
<td>org.hibernate.dialect.Oracle9iDialect</td>
</tr>
<tr>
<td>Oracle 10g</td>
<td>org.hibernate.dialect.Oracle10gDialect</td>
</tr>
<tr>
<td>Sybase</td>
<td>org.hibernate.dialect.SybaseDialect</td>
</tr>
<tr>
<td>Sybase Anywhere</td>
<td>org.hibernate.dialect.SybaseAnywhereDialect</td>
</tr>
<tr>
<td>Microsoft SQL Server</td>
<td>org.hibernate.dialect.SQLServerDialect</td>
</tr>
<tr>
<td>SAP DB</td>
<td>org.hibernate.dialect.SAPDBDialect</td>
</tr>
<tr>
<td>Informix</td>
<td>org.hibernate.dialect.InformixDialect</td>
</tr>
<tr>
<td>HypersonicSQL</td>
<td>org.hibernate.dialect.HSQLDialect</td>
</tr>
<tr>
<td>Ingres</td>
<td>org.hibernate.dialect.IngresDialect</td>
</tr>
<tr>
<td>Progress</td>
<td>org.hibernate.dialect.ProgressDialect</td>
</tr>
<tr>
<td>Mckoi SQL</td>
<td>org.hibernate.dialect.MckoiDialect</td>
</tr>
<tr>
<td>Interbase</td>
<td>org.hibernate.dialect.InterbaseDialect</td>
</tr>
<tr>
<td>Pointbase</td>
<td>org.hibernate.dialect.PointbaseDialect</td>
</tr>
<tr>
<td>FrontBase</td>
<td>org.hibernate.dialect.FrontbaseDialect</td>
</tr>
<tr>
<td>Firebird</td>
<td>org.hibernate.dialect.FirebirdDialect</td>
</tr>
</tbody>
</table>
<h3 id="JNDI数据源的连接属性">JNDI数据源的连接属性</h3><p>JNDI: Java Naming Directory Interface,Java命名目录接口。</p>
<ul>
<li>hibernate.connection.datasource：指定数据源JNDI名字。</li>
<li>hibernate.jndi.url：指定JNDI提供者的URL，该属性是可选的。如果JNDI与HIbernate持久化访问的代码处在同一个应用中。则无须指定该属性。</li>
<li>hibernate.jndi.class：指定JND InitialContextFactory的实现类，该属性也是可选的。如果JNDI与HIbernate持久化访问的代码处在同一个应用中。则无须指定该属性。</li>
<li>hibernate.connection.username：该属性是可选的。</li>
<li>hibernate.connection.passowrd：该属性是可选的。</li>
</ul>
<p>虽然设置数据库方言并不是必需的，但对于优化持久层访问很有必要。</p>
<h3 id="Hibernate事务属性">Hibernate事务属性</h3><ul>
<li>hibernate.transaction.factory_class:指定Hibernate所用的事务工厂的类型，该属性值必须是TransactionFactory的直接或间接子类。</li>
<li>jta.UserTransaction：该属性值是一个JNDI名，Hibernate将使用JTATransactionFactory从应用服务器获取JTA UserTransaction。</li>
<li>hibernate.transaction.manager_lookup_class：该属性值应为一个TransactionManagerLookup类名，当使用JVM级别的缓存时，或在JTA环境中使用hilo生成器策略时，需要该类。</li>
<li>hibernate.transaction.flush_before_completion：指定Session是否在事务完成后自动将数据刷新到底层受苦。该属性值只能为true或false。现在更好的方法是使用Context相关的Session管理。</li>
<li>hibernate.transaction.auto_close_session：指定是否在事务结束后自动关闭Session。该属性只能是true或false。现在更好的方法是使用Context相关的Session管理。</li>
</ul>
<h3 id="二级缓存相关属性">二级缓存相关属性</h3><ul>
<li>hibernate.cache.provider_class：该属性用于设置二级缓存CacheProvider的类名</li>
<li>hibernate.cache.user_minimal_puts：</li>
<li>hibernate.cache.use_second_level_cache：</li>
<li>hibernate.cache.query_cache_factory：</li>
<li>hibernate.cache.region_prefix：</li>
<li>hibernate.cache.use_structured_entries：</li>
</ul>
<h3 id="外连接抓取属性">外连接抓取属性</h3><p>将hibernate.max_fetch_depth设为0，将在全局范围内禁止外连接抓取，设为1或更高值能启用N-1或1-1的外连接抓取。除此之外，还应该在映射文件中通过fetch=”join”来指定这种外连接抓取。</p>
<h3 id="其他常用的配置属性">其他常用的配置属性</h3><ul>
<li>hibernate.show_sql：是否在控制台打印Hibernate生成的sql语句。</li>
<li>hibernate.format_sql：是否将SQL语句格式化。</li>
<li>hibernate.use_sql_comments：是否在Hibernate生成的SQL语句中添加有助于调试的注释。前三个取值只能是true或false</li>
<li>hibernate.jdbc.fetch_size：指定JDBC抓取数量的大小，它可接受一个整数值，其实质是调用Statement.setFetchSize()方法</li>
<li>hibernate.jdbc.batch_size：指定Hibernate使用JDBC2的批量更新的大小，它接受一个整数值，建议取5到30之间的值。</li>
<li>hibernate.connection.autocommit：设置是否自动提交。通常不建议打开自动提交。</li>
<li>hibernate.hbm2ddl.auto：设置当创建SessionFactory时，是否根据映射文件自动建立数据库表。如果使用create-drop值，显示关闭SessionFactory时，将Drop刚建的数据表。该属性可以为update、create和create-drop三个值。</li>
</ul>
<h2 id="深入理解持久化对象">深入理解持久化对象</h2><h3 id="持久化类的要求">持久化类的要求</h3><ul>
<li>提供一个无参数的构造器</li>
<li>提供一个标识属性，标识属性通常映射数据库表的主键字段。可以是任何名字，可以使用基本类型及其包装类，java.lang.String，java.util.Date。如果是联合主键，甚至可以用一个用户自定义的类，也可以不指定任何标识属性，而在配置文件中将多个普通类型映射成一个联合主键，但通常不推荐这么做。主键建议使用包装类型而不是基本类型。</li>
<li>没有标识可能导致Hibernate很多功能没法使用。Hibernate建议使用可以为空的类型来作为标识属性的类型，因此应该尽量避免使用基本数据类型。</li>
<li>为持久化类的每个属性提供setter和getter方法。Hibernate默认采用属性方式访问持久化类的属性。setX、getX、isX是被认可的。</li>
<li>使用非final的类。同时应避免在非final类中声明public final的方法。如果有这种方法，必须通过设置lazy=”false”来明确地禁用代理。</li>
<li>重写equals()和hashCode()方法。需要放入Set中（当进行关联映射时，推荐这么做），通常是使用判断标志值的方法。遗憾的是，对采用自动生成标识的对象不能使用这种方法。Hibernate仅为那些持久化对象指定标识值，一个新创建的实例将不会有任何标识值，通过保存一个对象将会给它赋标识值。如果equals()和hashCode()是基于标识值的，则其hashCode返回值会发生改变，这将违反Set规则。当我们想要重用脱管实例时，该实例所属的持久化类也应该重写equals()和hashCode()</li>
</ul>
<h3 id="持久化对象的状态">持久化对象的状态</h3><ul>
<li>瞬态：对象由new操作符创建，且尚未与Hibernate Session 关联的对象。不会被持久化到数据库中，也不会被赋予持久化标识。使用Hibernate Session可以将其变为持久化状态。</li>
<li>持久化：实例对应到数据库记录，并拥有一个持久化标识。持久化对象可以是刚刚保存的也可以是刚加载的，必须与指定的Hibernate Session关联。Hibernate会检测到处于持久化状态对象的改动，在当前操作执行完成时将对象数据写会数据库，不需要手动update。</li>
<li>脱管：某个实例曾经处于持久化状态，但随着与之关联的Session关闭，该对象处于脱管状态。</li>
</ul>
<p><img src="http://fh-1.qiniudn.com/PO_lifecycle.jpg" alt="持久化对象的状态演化图"></p>
<h3 id="改变持久化对象状态的方法">改变持久化对象状态的方法</h3><p>save()和persist()方法</p>
<ol>
<li>如果News的标识属性是generated，也就是说指定了主键生成器，那么Hibernate将会在执行save方法时自动生成标识属性值，并将该标识属性值分配给该News对象。</li>
<li>如果News的标识属性是assigned类型的，或者是联合主键，那么该标识属性值应当在调用save之前手动赋给News对象。</li>
</ol>
<p>Hibernate之所以提供与save( )功能几乎完全类似的persist( )方法，一方面是为了照顾JPA的用法习惯。另一方面save和persist还有一个区别：使用save( )方法保存持久化对象时，该方法返回该持久化对象的标识属性值即对应记录的主键值；但persist( )方法保存持久化对象时，没有任何返回值。因为save方法需要立即返回持久化对象的标识属性值，所以程序执行save( )方法时会立即将持久化对象对应的数据插入数据库。而persist方法则保证当它在一个事物外部被调用时，并不立即转换成insert语句，这个功能是很有用的，尤其当我们封装一个长会话流程的时候，persist就显得尤为重要了。</p>
<p>load( )与get( )：<br>也可以通过load( )来加载一个持久化实例，这种加载就是根据持久化类的标识属性值加载持久化实例———其实质就是根据主键从数据表中加载一条新记录。News n=session.load(News.class,new Integer(pk))；pk就是需要加载的持久化实例的标识属性。<br>如果没有匹配的数据库记录，load( )方法可能抛出HibernateException异常；如果我们在类映射文件中指定了延迟加载，则load( )方法会返回一个未初始化的代理对象，这个代理对象并没有装载数据记录，直到程序调用该代理对象的某方法时，Hibernate才会去访问数据库。<br>如果希望在某对象中创建一个指向另一个对象的关联，又不想在从数据库中装载该对象的同时装载相关联的所有对象，这种延迟加载的方式就非常有用了。<br>与load( )方法类似的是get( )方法，get( )方法也用于根据主键装载持久化实例，但get( )方法会立刻访问数据库，如果没有对应的记录，get( )方法返回null，而不是返回一个代理对象。<br>一旦加载了该持久化实例后，该实体就处于持久化状态，在代码中对持久化实例所做的修改，例如：n.setTitle(“新标题”);这种修改将被保存到数据库，对标题的修改被映射成修改数据表的特定行的特定列。<br>程序对持久化实例所做的修改会在Session flush之前被自动保存到数据库，无需程序调用其他方法(不需要调用update方法)来将修改持久化。也就是说，修改对象最简单的方法就是在Session处于打开状态时load它，然后直接修改即可。<br>对于一个曾经持久化过的、但现在已脱离Session管理的持久化对象，我们把它称为处于脱管状态。当我们修改脱管对象的状态后，程序应该使用新的Session来保存这些修改。Hibernate提供了update( )、merge( )和updateOrSave( )等方法来保存这些修改。<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">News</span> <span class="keyword">n</span>=firstSession.load(<span class="keyword">News</span>.<span class="keyword">class</span>,new Integer(pk));  </span><br><span class="line">firstSession.<span class="keyword">close</span>();  </span><br><span class="line"><span class="keyword">n</span>.setTitle(<span class="string">"新标题"</span>);  </span><br><span class="line">Session secondSession=HibernateSessionFactory.getSession();  </span><br><span class="line">secondSession.<span class="keyword">update</span>(<span class="keyword">n</span>);</span><br></pre></td></tr></table></figure></p>
<p>当我们用另一个Session来保存这种修改后，该脱管对象再次回到Session的管理之下，也就再次回到持久化状态。<br>当需要使用update( )来保存程序对持久化对象所做的修改时，如果不清楚该对象是否曾经持久化过，那么程序可以选择使用updateOrSave( )方法，该方法自动判断该对象是否曾经持久化，如果曾经持久化过，就使用update方法，否则将使用save操作。<br>merge( )方法也可将程序对脱管对象所做的修改保存到数据库，但merge方法与update方法最大的区别就是：merge( )方法不会持久化给定对象。举例来说，当我们执行session.update(a)代码后，a对象将会变成持久化状态；而执行session.merge(a)代码后，a对象依然不是持久化状态，a对象依然不会被关联到Session上。<br>当程序使用merge()方法来保存程序对脱管对象所做的修改时，如果Session中存在相同持久化标识的持久化对象，merge()方法里提供对象的状态将覆盖原有持久化实例的状态。如果Session中没有相应的持久化实例，则尝试从数据库中加载，或创建新的持久化实例，最后返回持久化实例。<br>merge()方法作用只是将当前对象的状态信息保存到数据库，并不会将该对象转换为持久化状态。<br>当我们使用load()和get()方法来加载持久化对象时，还可以指定一个”锁模式”参数。</p>
<p>save():保存持久化对象，在数据库中新增加一条数据<br>saveOrUpdate()保存或者是更新，该方法根据id标签的unsaved-value属性值决定执行新增加一条记录或者是更新。<br>get()根据标识符属性获得一个持久化对象，如果未找到，则返回null<br>load()该方法根据标识符属性加在一个持久化对象，如果未找到，则抛出异常<br>update() 该方法对托管状态的对象重新完成持久化，更新数据库中的数据<br>delete()删除数据库中的一条记录，不过需要先使用get() or  load() 获取持久化对象<br>close()关闭当前的session对象，并且清空该对象中的数据<br>evict()用于清除session缓存中的某一个对象<br>clear()清除Session中的所有缓存对象。</p>
<h2 id="映射">映射</h2><p> 在Hibernate中使用Annotation，跟以前xml配置的方式相比： </p>
<ol>
<li>仍然需要cfg.xml </li>
<li>在cfg.xml中需要配置要通过注解来配置的类，例如：  <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;mapping <span class="keyword">package</span>=<span class="string">"test.animals"</span>/&gt; </span><br><span class="line">&lt;mapping <span class="class"><span class="keyword">class</span></span>=<span class="string">"test.Flight"</span>/&gt;</span><br></pre></td></tr></table></figure></li>
<li>程序里面，原来的new Configuration()的地方，可以变成：new AnnotationConfiguration()，也可以不用改。 </li>
<li>可以通过编程的方式来添加要映射的类，例如：  <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">new <span class="function"><span class="title">AnnotationConfiguration</span><span class="params">()</span></span>.<span class="function"><span class="title">addPackage</span><span class="params">(<span class="string">"test.animals"</span>)</span></span> </span><br><span class="line">          .<span class="function"><span class="title">addAnnotatedClass</span><span class="params">(Flight.class)</span></span></span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="映射实体">映射实体</h3><ul>
<li>@Entity，注册在类头上，将一个类声明为一个实体bean(即一个持久化POJO类) 。 </li>
<li><p>@Table，注册在类头上，注解声明了该实体bean映射指定的表（table ）。 </p>
<p>  @Table元素有name、schema、catalog 和 uniqueConstraints属性，如果需要可以指定相应的值. 结合使用@UniqueConstraint注解可以定义表的唯一约束(unique constraint) (对于绑定到单列的唯一约束,请参考@Column注解)</p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Table</span>(name=<span class="string">"tbl_sky"</span>, uniqueConstraints = &#123;<span class="variable">@UniqueConstraint</span>(columnNames=&#123;<span class="string">"month"</span>, <span class="string">"day"</span>&#125;)&#125;)</span><br></pre></td></tr></table></figure>
<p>  上面这个例子中,在month和day这两个字段上定义唯一约束. 注意columnNames数组中的值指的是逻辑列名.</p>
</li>
</ul>
<h3 id="映射属性">映射属性</h3><p>在对一个类进行注解时,你可以选择对它的的属性或者方法进行注解,根据你的选择,Hibernate的访问类型分别为 field或property. EJ3规范要求在需要访问的元素上进行注解声明,例如,如果访问类型为 property就要在getter方法上进行注解声明, 如果访问类型为 field就要在字段上进行注解声明.应该尽量避免混合使用这两种访问类型. Hibernate根据@Id 或 @EmbeddedId的位置来判断访问类型.</p>
<p>@Id用来注册主属性，@GeneratedValue用来注册主属性的生成策略，@Column用来注册属性，@Version用来注册乐观锁，@Transient用来注册不是属性。 </p>
<p>@Transient注册在多余的属性或多余的getter上，但是必须与以上的@Column等对应。 </p>
<p>Hibernate Annotations还支持将内置的枚举类型映射到一个顺序列(保存了相应的序列值) 或一个字符串类型的列(保存相应的字符串).默认是保存枚举的序列值, 但是你可以通过@Enumerated注解来进行调整</p>
<p>在核心的Java API中并没有定义时间精度(temporal precision). 因此处理时间类型数据时,你还需要定义将其存储在数据库中所预期的精度. 在数据库中,表示时间类型的数据有DATE, TIME, 和 TIMESTAMP三种精度(即单纯的日期,时间,或者两者兼备). 可使用@Temporal注解来调整精度.</p>
<p>@Lob注解表示属性将被持久化为Blob或者Clob类型, 具体取决于属性的类型, java.sql.Clob, Character[], char[] 和 java.lang.String这些类型的属性都被持久化为Clob类型, 而java.sql.Blob, Byte[], byte[] 和 serializable类型则被持久化为Blob类型.</p>
<h4 id="非主属性">非主属性</h4><p>@Column<br>   标识属性对应的字段，示例：@Column(name=”userName”) </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Column</span>( </span><br><span class="line">    name=<span class="string">"columnName"</span>;                                (<span class="number">1</span>) </span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">unique</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">false</span></span>;                   (<span class="number">2</span>) </span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">nullable</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">true</span></span>;                  (<span class="number">3</span>) </span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">insertable</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">true</span></span>;                (<span class="number">4</span>) </span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">updatable</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">true</span></span>;                 (<span class="number">5</span>) </span><br><span class="line">    <span class="function">String <span class="title">columnDefinition</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;             (<span class="number">6</span>) </span><br><span class="line">    <span class="function">String <span class="title">table</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;                        (<span class="number">7</span>) </span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">length</span><span class="params">()</span> <span class="keyword">default</span> 255</span>;                         (<span class="number">8</span>) </span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">precision</span><span class="params">()</span> <span class="keyword">default</span> 0</span>; <span class="comment">// decimal precision   (9) </span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">scale</span><span class="params">()</span> <span class="keyword">default</span> 0</span>; <span class="comment">// decimal scale           (10)</span></span><br></pre></td></tr></table></figure>
<p>(1) name 可选,列名(默认值是属性名)<br>(2) unique 可选,是否在该列上设置唯一约束(默认值false)<br>(3) nullable 可选,是否设置该列的值可以为空(默认值false)<br>(4) insertable 可选,该列是否作为生成的insert语句中的一个列(默认值true)<br>(5) updatable 可选,该列是否作为生成的update语句中的一个列(默认值true)<br>(6) columnDefinition 可选: 为这个特定列覆盖SQL DDL片段 (这可能导致无法在不同数据库间移植)<br>(7) table 可选,定义对应的表(默认为主表)<br>(8) length 可选,列长度(默认值255)<br>(9) precision 可选,列十进制精度(decimal precision)(默认值0)<br>(10) scale 可选,如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)<br>如果某属性没有注解,该属性将遵守下面的规则:</p>
<p><strong>无注解之属性的默认值</strong></p>
<p>如果属性为单一类型,则映射为@Basic<br>否则,如果属性对应的类型定义了@Embeddable注解,则映射为@Embedded<br>否则,如果属性对应的类型实现了Serializable, 则属性被映射为@Basic并在一个列中保存该对象的serialized版本<br>否则,如果该属性的类型为java.sql.Clob 或 java.sql.Blob,则作为@Lob并映射到适当的LobType.</p>
<h4 id="主属性">主属性</h4><p>@Id，标识这个属性是实体类的唯一识别的值。<br>注意：这个注解只能标注单一列构成的主键，有两个字段组成的联合主键由其他注解标识。 </p>
<p>@Id，只是标识这个属性是主键，但是并没有指出其生成策略<br>如果仅仅写出@Id，即是使用默认生成策略，如： </p>
<p><strong>JPA通用策略生成器</strong><br>JPA提供的四种标准用法为TABLE，SEQUENCE，IDENTITY，AUTO，默认AUTO</p>
<ul>
<li>AUTO - 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.</li>
<li>TABLE - 使用一个特定的数据库表格来保存主键</li>
<li>IDENTITY - 主键由数据库自动生成(主要是自动增长型)</li>
<li>SEQUENCE - 根据地层数据库的序列来生成主键，条件是数据库支持序列，主要是Oracle</li>
</ul>
<p><strong>hibernate主键策略生成器</strong></p>
<p>hibernate提供多种主键生成策略，有点是类似于JPA，有的是hibernate特有： </p>
<ul>
<li>native: 对于 oracle 采用 Sequence 方式，对于MySQL 和 SQL Server 采用identity（自增主键生成机制），native就是将主键的生成工作交由数据库完成，hibernate不管（很常用）。 </li>
<li>uuid: 采用128位的uuid算法生成主键，uuid被编码为一个32位16进制数字的字符串。占用空间大（字符串类型）。 </li>
<li>hilo: 使用hilo生成策略，要在数据库中建立一张额外的表，默认表名为hibernate_* unique_key,默认字段为integer类型，名称是next_hi（比较少用）。 </li>
<li>assigned: 在插入数据的时候主键由程序处理（很常用），这是 <generator>元素没有指定时的默认生成策略。等同于JPA中的AUTO。 </generator></li>
<li>identity: 使用SQL Server 和 MySQL 的自增字段，这个方法不能放到 Oracle 中，Oracle 不支持自增字段，要设定sequence（MySQL 和 SQL Server 中很常用）。等同于JPA中的INDENTITY。 </li>
<li>select: 使用触发器生成主键（主要用于早期的数据库主键生成机制，少用）。 </li>
<li>sequence: 调用底层数据库的序列来生成主键，要设定序列名，不然hibernate无法找到。 </li>
<li>seqhilo: 通过hilo算法实现，但是主键历史保存在Sequence中，适用于支持 Sequence 的数据库，如 Oracle（比较少用） </li>
<li>increment: 插入数据的时候hibernate会给主键添加一个自增的主键，但是一个hibernate实例就维护一个计数器，所以在多个实例运行的时候不能使用这个方法。 </li>
<li>foreign: 使用另外一个相关联的对象的主键。通常和<one-to-one>联合起来使用。 </one-to-one></li>
<li>guid: 采用数据库底层的guid算法机制，对应MYSQL的uuid()函数，SQL Server的newid()函数，ORACLE的rawtohex(sys_guid())函数等。 </li>
<li>uuid.hex: 看uuid，建议用uuid替换。 </li>
<li>sequence-identity: sequence策略的扩展，采用立即检索策略来获取sequence值，需要JDBC3.0和JDK4以上（含1.4）版本 </li>
</ul>
<p>hibernate提供了多种生成器供选择,基于Annotation的方式通过@GenericGenerator实现.<br>hibernate每种主键生成策略提供接口org.hibernate.id.IdentifierGenerator的实现类,如果要实现自定义的主键生成策略也必须实现此接口</p>
<p>如果想使用Oracle支持的sequence取主键，必须通过@GeneratedValue来指定生成策略，而由@SequenceGenerator指定如何使用sequence。 </p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Id</span></span><br><span class="line"><span class="variable">@GeneratedValue</span>(strategy = GenerationType.SEQUENCE,generator=<span class="string">"payablemoney_seq"</span>)</span><br><span class="line"><span class="variable">@SequenceGenerator</span>(name=<span class="string">"payablemoney_seq"</span>, sequenceName=<span class="string">"seq_payment"</span>)</span><br></pre></td></tr></table></figure>
<p>@SequenceGenerator定义 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Target</span>(&#123;TYPE, METHOD, FIELD&#125;)   </span><br><span class="line"><span class="annotation">@Retention</span>(RUNTIME)  </span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> SequenceGenerator &#123;  </span><br><span class="line"> <span class="function">String <span class="title">name</span><span class="params">()</span></span>;  </span><br><span class="line"> <span class="function">String <span class="title">sequenceName</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;  </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">initialValue</span><span class="params">()</span> <span class="keyword">default</span> 0</span>;  </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">allocationSize</span><span class="params">()</span> <span class="keyword">default</span> 50</span>;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>name属性表示该表主键生成策略的名称，它被引用在@GeneratedValue中设置的”generator”值中。<br>sequenceName属性表示生成策略用到的数据库序列名称。<br>initialValue表示主键初识值，默认为0。<br>allocationSize表示每次主键值增加的大小，例如设置成1，则表示每次创建新记录后自动加1，默认为50。 </p>
<p><strong>自定义主键生成策略</strong><br>自定义主键生成策略，由@GenericGenerator实现。<br>hibernate在JPA的基础上进行了扩展，可以用一下方式引入hibernate独有的主键生成策略，就是通过@GenericGenerator加入的。</p>
<p>比如说，JPA标准用法<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Id</span>  </span><br><span class="line"><span class="variable">@GeneratedValue</span>(GenerationType.AUTO)</span><br></pre></td></tr></table></figure></p>
<p>就可以用hibernate特有以下用法来实现<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@GeneratedValue</span>(generator = <span class="string">"paymentableGenerator"</span>)    </span><br><span class="line"><span class="variable">@GenericGenerator</span>(name = <span class="string">"paymentableGenerator"</span>, strategy = <span class="string">"assigned"</span>)</span><br></pre></td></tr></table></figure></p>
<p>@GenericGenerator有三个属性</p>
<ul>
<li>name属性指定生成器名称。 </li>
<li>strategy属性指定具体生成器的类名。 </li>
<li>parameters得到strategy指定的具体生成器所用到的参数。 </li>
</ul>
<h4 id="乐观锁和不用持久化">乐观锁和不用持久化</h4><ul>
<li>@Version<br>  标识这个属性用来映射乐观锁的version。entity manager使用该字段来检测更新冲突(防止更新丢失,请参考last-commit-wins策略).<br>  根据EJB3规范,version列可以是numeric类型(推荐方式)也可以是timestamp类型. Hibernate支持任何自定义类型,只要该类型实现了UserVersionType. </li>
<li>@Transient<br>标识这个属性不用持久化 </li>
</ul>
<h4 id="复合属性—组件映射">复合属性—组件映射</h4><ul>
<li><p>@Embeddable 【小对象的头上】 </p>
<p>  标识实体中可以定义一个嵌入式组件(embedded component)。组件类必须在类一级定义@Embeddable注解。 </p>
</li>
<li><p>@Embedded 【大对象的属性头上】 </p>
<p>  引用定义的小对象。 </p>
<p>  使用@Embedded和 @AttributeOverride注解可以覆盖该属性对应的嵌入式对象的列映射</p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Embedded</span></span><br><span class="line"><span class="variable">@AttributeOverrides</span>( &#123;</span><br><span class="line">    <span class="variable">@AttributeOverride</span>(name=<span class="string">"iso2"</span>, column = <span class="variable">@Column</span>(name=<span class="string">"bornIso2"</span>) ),</span><br><span class="line">    <span class="variable">@AttributeOverride</span>(name=<span class="string">"name"</span>, column = <span class="variable">@Column</span>(name=<span class="string">"bornCountryName"</span>) ) &#125; )</span><br><span class="line">Country bornIn;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="复合属性—复合主键">复合属性—复合主键</h4><p>下面是定义组合主键的几种语法:</p>
<ul>
<li>将组件类注解为@Embeddable,并将组件的属性注解为@Id</li>
<li>将组件的属性注解为@EmbeddedId</li>
<li><p>将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id</p>
</li>
<li><p>@Embeddable 【小对象的头上】 </p>
<p>  标识实体中可以定义一个嵌入式组件(embedded component)。组件类必须在类一级定义@Embeddable注解。<br>  注意：如果这个小对象作为复合主键，一定要实现Serializable接口。这并不是注解决定的，而是Hibernate的主键都需要实现Serializable接口。 </p>
</li>
<li><p>@EmbeddedId  【大对象的属性头上】 </p>
<p>  引用定义的小对象作为主键。<br>  注意：不需要再使用@Id注解。 </p>
</li>
</ul>
<h3 id="集合映射">集合映射</h3><p>你可以对 Collection ,List (指有序列表, 而不是索引列表), Map和Set这几种类型进行映射. EJB3规范定义了怎么样使用@javax.persistence.OrderBy 注解来对有序列表进行映射： 该注解接受的参数格式：用逗号隔开的(目标实体)属性名及排序指令, 如firstname asc, age desc,如果该参数为空,则默认以id对该集合进行排序. 如果某个集合在数据库中对应一个关联表(association table)的话,你不能在这个集合属性上面使用@OrderBy注解. 对于这种情况的处理方法,请参考Hibernate Annotation Extensions. EJB3 允许你利用目标实体的一个属性作为Map的key, 这个属性可以用@MapKey(name=”myProperty”)来声明. 如果使用@MapKey注解的时候不提供属性名, 系统默认使用目标实体的主键. map的key使用和属性相同的列：不需要为map key定义专用的列，因为map key实际上就表达了一个目标属性。 注意一旦加载,key不再和属性保持同步, 也就是说,如果你改变了该属性的值,在你的Java模型中的key不会自动更新 (请参考Hibernate Annotation Extensions). 很多人被<map>和@MapKey弄糊涂了。 其他它们有两点区别.@MapKey目前还有一些限制,详情请查看论坛或者 我们的JIRA缺陷系统。 注意一旦加载,key不再和属性保持同步, 也就是说,如果你改变了该属性的值,在你的Java模型中的key不会自动更新. (Hibernate 3中Map支持的方式在当前的发布版中还未得到支持).</map></p>
<p>Hibernate将集合分以下几类.</p>
<table>
<thead>
<tr>
<th>语义</th>
<th>Java实现类</th>
<th>注解</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bag 语义</td>
<td>java.util.List, java.util.Collection</td>
<td>@org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany</td>
</tr>
<tr>
<td>List 语义</td>
<td>java.util.List</td>
<td>(@org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany) 以及 @org.hibernate.annotations.IndexColumn</td>
</tr>
<tr>
<td>Set 语义</td>
<td>java.util.Set</td>
<td>@org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany</td>
</tr>
<tr>
<td>Map 语义</td>
<td>java.util.Map</td>
<td>(@org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany) 以及 (空 或 @org.hibernate.annotations.MapKey/MapKeyManyToMany(支持真正的map), 或 @javax.persistence.MapKey</td>
</tr>
</tbody>
</table>
<p>从上面可以明确地看到,没有@org.hibernate.annotations.IndexColumn 注解的java.util.List集合将被看作bag类.<br>EJB3规范不支持原始类型,核心类型,嵌入式对象的集合.但是Hibernate对此提供了支持</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Entity</span> <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">City</span> </span>&#123;</span><br><span class="line">    <span class="annotation">@OneToMany</span>(mappedBy=<span class="string">"city"</span>)</span><br><span class="line">    <span class="annotation">@OrderBy</span>(<span class="string">"streetName"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;Street&gt; <span class="title">getStreets</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> streets;</span><br><span class="line">    &#125;</span><br><span class="line">...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Entity</span> <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Street</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getStreetName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> streetName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@ManyToOne</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> City <span class="title">getCity</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> city;</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Software</span> </span>&#123;</span><br><span class="line">    <span class="annotation">@OneToMany</span>(mappedBy=<span class="string">"software"</span>)</span><br><span class="line">    <span class="annotation">@MapKey</span>(name=<span class="string">"codeName"</span>)</span><br><span class="line">    <span class="keyword">public</span> Map&lt;String, Version&gt; getVersions() &#123;</span><br><span class="line">        <span class="keyword">return</span> versions;</span><br><span class="line">    &#125;</span><br><span class="line">...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@Table</span>(name=<span class="string">"tbl_version"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Version</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getCodeName</span><span class="params">()</span> </span>&#123;...&#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@ManyToOne</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Software <span class="title">getSoftware</span><span class="params">()</span> </span>&#123; ... &#125;</span><br><span class="line">...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面这个例子中,City 中包括了以streetName排序的Street的集合. 而Software中包括了以codeName作为 key和以Version作为值的Map.</p>
<p>除非集合为generic类型,否则你需要指定targetEntity. 这个注解属性接受的参数为目标实体的class.</p>
<p>Hibernate Annotations还支持核心类型集合(Integer, String, Enums, ……)、 可内嵌对象的集合,甚至基本类型数组.这就是所谓的元素集合.</p>
<p>元素集合可用@CollectionOfElements来注解(作为@OneToMany的替代). 为了定义集合表(译注：即存放集合元素的表,与下面提到的主表对应),要在关联属性上使用@JoinTable注解, joinColumns定义了介乎实体主表与集合表之间的连接字段(inverseJoincolumn是无效的且其值应为空). 对于核心类型的集合或基本类型数组,你可以在关联属性上用@Column来覆盖存放元素值的字段的定义. 你还可以用@AttributeOverride来覆盖存放可内嵌对象的字段的定义. 要访问集合元素,需要将该注解的name属性值设置为”element”(“element”用于核心类型,而”element.serial” 用于嵌入式对象的serial属性).要访问集合的index/key,则将该注解的name属性值设置为”key”.</p>
<h3 id="映射继承关系">映射继承关系</h3><p>EJB3支持三种类型的继承映射:</p>
<ul>
<li>每个类一张表(Table per class)策略: 在Hibernate中对应<union-class>元素:</union-class></li>
<li>每个类层次结构一张表(Single table per class hierarchy)策略:在Hibernate中对应<subclass>元素</subclass></li>
<li>连接的子类(Joined subclasses)策略:在Hibernate中对应 <joined-subclass>元素</joined-subclass></li>
</ul>
<p>你可以用 @Inheritance注解来定义所选择的策略. 这个注解需要在每个类层次结构(class hierarchy) 最顶端的实体类上使用.</p>
<h4 id="每个类一张表">每个类一张表</h4><p>这种策略有很多缺点(例如:多态查询和关联),EJB3规范, Hibernate参考手册, Hibernate in Action,以及其他许多地方都对此进行了描述和解释. Hibernate使用SQL UNION查询来实现这种策略. 通常使用场合是在一个继承层次结构的顶端:</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@Inheritance</span>(strategy = InheritanceType.TABLE_PER_CLASS)</span><br><span class="line">public class Flight implements Serializable&#123;...&#125;</span><br></pre></td></tr></table></figure>
<p>这种策略支持双向的一对多关联. 这里不支持IDENTITY生成器策略,因为id必须在多个表间共享. 当然,一旦使用这种策略就意味着你不能使用 AUTO 生成器和IDENTITY生成器.</p>
<h4 id="每个类层次结构一张表">每个类层次结构一张表</h4><p>整个继承层次结构中的父类和子类的所有属性都映射到同一个表中, 他们的实例通过一个辨别符(discriminator)列来区分.:</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@Inheritance</span>(strategy=InheritanceType.SINGLE_TABLE)</span><br><span class="line"><span class="variable">@DiscriminatorColumn</span>(</span><br><span class="line">    name=<span class="string">"planetype"</span>,</span><br><span class="line">    discriminatorType=DiscriminatorType.STRING</span><br><span class="line">)</span><br><span class="line"><span class="variable">@DiscriminatorValue</span>(<span class="string">"Plane"</span>)</span><br><span class="line">public class Plane &#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@DiscriminatorValue</span>(<span class="string">"A320"</span>)</span><br><span class="line">public class A320 extends Plane &#123; ... &#125;</span><br></pre></td></tr></table></figure>
<p>在上面这个例子中,Plane是父类,在这个类里面将继承策略定义为 <code>InheritanceType.SINGLE_TABLE</code>,并通过 @DiscriminatorColumn注解定义了辨别符列(还可以定义辨别符的类型). 最后,对于继承层次结构中的每个类,@DiscriminatorValue注解指定了用来辨别该类的值. 辨别符列的名字默认为 DTYPE,其默认值为实体名(在@Entity.name中定义)，其类型 为DiscriminatorType.STRING. A320是子类,如果不想使用默认的辨别符,只需要指定相应的值即可. 其他的如继承策略,辨别标志字段的类型都是自动设定的.</p>
<p>@Inheritance 和 @DiscriminatorColumn 注解只能用于实体层次结构的顶端.</p>
<h4 id="连接的子类">连接的子类</h4><p>当每个子类映射到一个表时, @PrimaryKeyJoinColumn 和@PrimaryKeyJoinColumns 注解定义了每个子类表关联到父类表的主键:</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@Inheritance</span>(strategy=InheritanceType.JOINED)</span><br><span class="line">public class Boat implements Serializable &#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">@Entity</span></span><br><span class="line">public class Ferry extends Boat &#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@PrimaryKeyJoinColumn</span>(name=<span class="string">"BOAT_ID"</span>)</span><br><span class="line">public class AmericaCupClass  extends Boat &#123; ... &#125;</span><br></pre></td></tr></table></figure>
<p>以上所有实体都使用了JOINED策略, Ferry表和Boat表使用同名的主键. 而AmericaCupClass表和Boat表使用了条件 <code>Boat.id = AmericaCupClass.BOAT_ID</code>进行关联.</p>
<h4 id="从父类继承的属性">从父类继承的属性</h4><p>有时候通过一个(技术上或业务上)父类共享一些公共属性是很有用的, 同时还不用将该父类作为映射的实体(也就是该实体没有对应的表). 这个时候你需要使用@MappedSuperclass注解来进行映射.</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@MappedSuperclass</span></span><br><span class="line">public class BaseEntity &#123;</span><br><span class="line">    <span class="variable">@Basic</span></span><br><span class="line">    <span class="variable">@Temporal</span>(TemporalType.TIMESTAMP)</span><br><span class="line">    public Date <span class="function">getLastUpdate</span>() &#123; ... &#125;</span><br><span class="line">    public String <span class="function">getLastUpdater</span>() &#123; ... &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">@Entity</span> class Order extends BaseEntity &#123;</span><br><span class="line">    <span class="variable">@Id</span> public Integer <span class="function">getId</span>() &#123; ... &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在数据库中,上面这个例子中的继承的层次结构最终以Order表的形式出现, 该表拥有id, lastUpdate 和 lastUpdater三个列.父类中的属性映射将复制到其子类实体. 注意这种情况下的父类不再处在继承层次结构的顶端.</p>
<p>注意：<br>注意,没有注解为@MappedSuperclass的父类中的属性将被忽略。<br>除非显式使用Hibernate annotation中的@AccessType注解, 否则将从继承层次结构的根实体中继承访问类型(包括字段或方法)。<br>这对于@Embeddable对象的父类中的属性持久化同样有效. 只需要使用@MappedSuperclass注解即可 (虽然这种方式不会纳入EJB3标准)。<br>可以将处在在映射继承层次结构的中间位置的类注解为@MappedSuperclass。<br>在继承层次结构中任何没有被注解为@MappedSuperclass 或@Entity的类都将被忽略。</p>
<p>你可以通过 @AttributeOverride注解覆盖实体父类中的定义的列. 这个注解只能在继承层次结构的顶端使用.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@MappedSuperclass</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FlyingObject</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAltitude</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> altitude;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Transient</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getMetricAltitude</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> metricAltitude;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@ManyToOne</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> PropulsionType <span class="title">getPropulsion</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> metricAltitude;</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@AttributeOverride</span>( name=<span class="string">"altitude"</span>, column = <span class="annotation">@Column</span>(name=<span class="string">"fld_altitude"</span>) )</span><br><span class="line"><span class="annotation">@AssociationOverride</span>( name=<span class="string">"propulsion"</span>, joinColumns = <span class="annotation">@JoinColumn</span>(name=<span class="string">"fld_propulsion_fk"</span>) )</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Plane</span> <span class="keyword">extends</span> <span class="title">FlyingObject</span> </span>&#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在上面这个例子中,altitude属性的值最终将持久化到Plane 表的<code>fld_altitude</code>列.而名为propulsion的关联则保存在<code>fld_propulsion_fk</code>外间列.</p>
<p>你可以为@Entity和@MappedSuperclass注解的类 以及那些对象为@Embeddable的属性定义 @AttributeOverride和@AssociationOverride.</p>
<h3 id="关联关系映射">关联关系映射</h3><h4 id="关联关系映射—简介">关联关系映射—简介</h4><p>在hibernate中，支持对象之间的关联关系映射，这样可以减少我们的dao操作，操作一个对象的时候，就可以顺带操作它的关联对象。我们知道，hibernate支持三种关联关系，1:1，1:M，M:N。但，这只是对象之间的关系。数据库的设计当然也支持1:1，1:M，M:N三种关系。比如，我们经常说的1:M，就是把1这张表的主键拿到多那边做外键。但是，很多同学经常迷惑，为什么网上介绍的1:M，比我们讲的还要复杂的多？我们只需要<set>和<many-to-one>，但是网上介绍的还有一种使用<set>和<join>的？这里我们就不得不提出 “数据库设计的降级使用”这个概念了。 </join></set></many-to-one></set></p>
<h4 id="关联关系映射—数据库降级使用">关联关系映射—数据库降级使用</h4><p>标准的1:M </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+----------+          +----------+</span><br><span class="line">|<span class="string">tbl_parent</span>|<span class="string">          </span>|<span class="string">tbl_child </span>|<span class="string"> </span><br><span class="line">+----------+          +----------+</span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;  </span>|<span class="string">          </span>|<span class="string"> uuid&lt;PK&gt; </span>|</span><br><span class="line">+----------+          |<span class="string"> puuid&lt;FK&gt;</span>|</span><br><span class="line">                      +----------+</span><br></pre></td></tr></table></figure>
<p>标准的M:N </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+-----------+     +---------------+     +-----------+ </span><br><span class="line">|<span class="string">tbl_student</span>|<span class="string">     </span>|<span class="string">   tbl_grade   </span>|<span class="string">     </span>|<span class="string">tbl_course </span>|<span class="string">  </span><br><span class="line">+-----------+     +---------------+     +-----------+ </span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">     </span>|<span class="string"> suuid&lt;PK&gt;&lt;FK&gt; </span>|<span class="string">     </span>|<span class="string">cuuid&lt;PK&gt;  </span>|<span class="string"> </span><br><span class="line">+-----------+     </span>|<span class="string"> cuuid&lt;PK&gt;&lt;FK&gt; </span>|<span class="string">     +-----------+ </span><br><span class="line">                  +---------------+</span></span><br></pre></td></tr></table></figure>
<p>将M:N的数据库设计降级为1:M使用 </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+-----------+     +-----------------------+     +-----------+ </span><br><span class="line">|<span class="string">tbl_parent </span>|<span class="string">     </span>|<span class="string"> tbl_parent_child      </span>|<span class="string">     </span>|<span class="string">tbl_child  </span>|<span class="string">  </span><br><span class="line">+-----------+     +-----------------------+     +-----------+ </span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">     </span>|<span class="string"> puuid&lt;PK&gt;&lt;FK&gt;         </span>|<span class="string">     </span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string"> </span><br><span class="line">+-----------+     </span>|<span class="string"> cuuid&lt;PK&gt;&lt;FK&gt;&lt;UNIQUE&gt; </span>|<span class="string">     +-----------+ </span><br><span class="line">                  +-----------------------+</span></span><br></pre></td></tr></table></figure>
<h4 id="关联关系映射—1:1—共享主键">关联关系映射—1:1—共享主键</h4><p>标准的1:1 </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+-----------+          +----------------+</span><br><span class="line">|<span class="string">tbl_product</span>|<span class="string">          </span>|<span class="string">tbl_product_info</span>|<span class="string"> </span><br><span class="line">+-----------+          +----------------+</span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">          </span>|<span class="string">  uuid&lt;PK&gt;&lt;FK&gt;  </span>|</span><br><span class="line">+-----------+          +----------------+</span><br></pre></td></tr></table></figure>
<ul>
<li><p>XML的配置 </p>
<p>  主1 【tbl_product】： </p>
  <figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="constant">one</span>-<span class="built_in">to</span>-<span class="constant">one</span> name= <span class="string">"info"</span> cascade=<span class="string">"all"</span>/&gt;</span><br></pre></td></tr></table></figure>
<p>  从1 【tbl_product_info】： </p>
  <figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="property">id</span> <span class="property">name</span>= <span class="string">"uuid"</span>&gt; </span><br><span class="line">&lt;generator <span class="type">class</span>=<span class="string">"foreign  【写死，使用外来生成策略】"</span>&gt; </span><br><span class="line">        &lt;param <span class="property">name</span>=<span class="string">"property"</span>&gt;product  【引用自己的Java属性名】 </span><br><span class="line">        &lt;/param&gt; </span><br><span class="line">&lt;/generator&gt; </span><br><span class="line">&lt;/<span class="property">id</span>&gt; </span><br><span class="line">&lt;one-<span class="keyword">to</span>-one <span class="property">name</span>= <span class="string">"product"</span>/&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>注解的配置 </p>
<p>  主1 【tbl_product】： </p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@OneToOne</span>(cascade=CascadeType.ALL) </span><br><span class="line"><span class="variable">@PrimaryKeyJoinColumn</span> </span><br><span class="line">private ProductInfoModel info;</span><br></pre></td></tr></table></figure>
<p>  从1 【tbl_product_info】： </p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Id</span> </span><br><span class="line"><span class="variable">@Column</span> </span><br><span class="line"><span class="variable">@GeneratedValue</span>(generator=<span class="string">"copy 【引用生成策略】"</span>) </span><br><span class="line"><span class="variable">@GenericGenerator</span>(name=<span class="string">"copy  【定义生成策略】"</span>,strategy=<span class="string">"foreign  【写死，使用外来策略】"</span>,parameters=<span class="variable">@Parameter</span>(name=<span class="string">"property"</span>,value=<span class="string">"product  【引用自己的Java属性】"</span>)) </span><br><span class="line">private int uuid; </span><br><span class="line"><span class="variable">@OneToOne</span>(mappedBy=<span class="string">"info  【引用对方的Java属性】"</span>) </span><br><span class="line">private ProductModel product;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="关联关系映射—1:M—外键">关联关系映射—1:M—外键</h4><p>标准的1:M </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+----------+          +----------+</span><br><span class="line">|<span class="string">tbl_parent</span>|<span class="string">          </span>|<span class="string">tbl_child </span>|<span class="string"> </span><br><span class="line">+----------+          +----------+</span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;  </span>|<span class="string">          </span>|<span class="string"> uuid&lt;PK&gt; </span>|</span><br><span class="line">+----------+          |<span class="string"> puuid&lt;FK&gt;</span>|</span><br><span class="line">                      +----------+</span><br></pre></td></tr></table></figure>
<ul>
<li><p>XML的配置</p>
<p>  1 【tbl_parent】： </p>
  <figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="keyword">set</span> <span class="property">name</span>= <span class="string">"children"</span>&gt; </span><br><span class="line">    &lt;key column=<span class="string">"puuid  【对方的数据库外键列名】"</span>/&gt; </span><br><span class="line">    &lt;one-<span class="keyword">to</span>-many <span class="type">class</span>=<span class="string">"cn.j avass.model.c.ChildModel  【对方的Java类名】"</span>/&gt; </span><br><span class="line">&lt;/<span class="keyword">set</span>&gt;</span><br></pre></td></tr></table></figure>
<p>  多 【tbl_child】： </p>
  <figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;many-<span class="keyword">to</span>-one <span class="property">name</span>=<span class="string">"parent"</span> column=<span class="string">"puuid 【自己的数据库外键列名】"</span>/&gt;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ul>
<li>注解的配置<br>  1 【tbl_parent】：   <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@OneToMany</span> </span><br><span class="line"><span class="variable">@JoinColumn</span>(name=<span class="string">"puuid 【对方的数据库外键列名】"</span>) </span><br><span class="line">private Set&lt;ChildModel&gt; children = new HashSet&lt;ChildModel&gt;();</span><br></pre></td></tr></table></figure>
  多 【tbl_child】：   <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@ManyToOne</span> </span><br><span class="line"><span class="variable">@JoinColumn</span>(name=<span class="string">"puuid 【自己的数据库外键列名】"</span>) </span><br><span class="line">private ParentModel parent;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="关联关系映射—M:N—联接表">关联关系映射—M:N—联接表</h4><p>标准的M:N </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+-----------+     +---------------+     +-----------+ </span><br><span class="line">|<span class="string">tbl_student</span>|<span class="string">     </span>|<span class="string">   tbl_grade   </span>|<span class="string">     </span>|<span class="string">tbl_course </span>|<span class="string">  </span><br><span class="line">+-----------+     +---------------+     +-----------+ </span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">     </span>|<span class="string"> suuid&lt;PK&gt;&lt;FK&gt; </span>|<span class="string">     </span>|<span class="string"> uuid&lt;PK&gt;  </span>|<span class="string"> </span><br><span class="line">+-----------+     </span>|<span class="string"> cuuid&lt;PK&gt;&lt;FK&gt; </span>|<span class="string">     +-----------+ </span><br><span class="line">                  +---------------+</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>XML的配置 </p>
  <figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="keyword">set</span> <span class="property">name</span>=<span class="string">"courses"</span> table=<span class="string">"tbl_grade  【联接表】"</span>&gt; </span><br><span class="line">    &lt;key column=<span class="string">"suuid 【联接表里代表自己的数据库字段名】"</span>/&gt; </span><br><span class="line">    &lt;many-<span class="keyword">to</span>-many column=<span class="string">"cuuid 【联接表里代表对方的数据库字段名】"</span> </span><br><span class="line">    <span class="type">class</span>=<span class="string">"cn.ja vass.model.e.CourseMode  【对方的类名】l"</span>/&gt; </span><br><span class="line">&lt;/<span class="keyword">set</span>&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>注解的配置 </p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@ManyToMany</span> </span><br><span class="line"><span class="variable">@JoinTable</span>( </span><br><span class="line">name=<span class="string">"tbl_grade  【联接表】"</span>, </span><br><span class="line">joinColumns=<span class="variable">@JoinColumn</span>(name=<span class="string">"suuid 【联接表里代表自己的数据库字段名】"</span>), </span><br><span class="line">inverseJoinColumns=<span class="variable">@JoinColumn</span>(name=<span class="string">"cuuid   【联接表里代表对方的数据库字段名】"</span> ) </span><br><span class="line">) </span><br><span class="line">private Set&lt;CourseModel&gt; courses = new HashSet&lt;CourseModel&gt;();</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>关联关系映射—1:1—引用外键 </p>
<p>标准的1:M </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+-----------+     +-----------------------+  </span><br><span class="line">|<span class="string">tbl_product</span>|<span class="string">     </span>|<span class="string"> tbl_product_info      </span>|<span class="string">  </span><br><span class="line">+-----------+     +-----------------------+ </span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">     </span>|<span class="string"> uuid&lt;PK&gt;              </span>|<span class="string"> </span><br><span class="line">+-----------+     </span>|<span class="string"> puuid&lt;FK&gt;&lt;UNIQUE&gt;     </span>|<span class="string"> </span><br><span class="line">                  +-----------------------+</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>XML的配置</p>
<p>  主1 【tbl_product】： </p>
  <figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="constant">one</span>-<span class="built_in">to</span>-<span class="constant">one</span> name=<span class="string">"info"</span> foreign-key= <span class="string">"puuid  【对方的数据库外键列名】"</span>  cascade=<span class="string">"all"</span>/&gt;</span><br></pre></td></tr></table></figure>
<p>  从1 【tbl_product_info】： </p>
  <figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;many-to-one <span class="variable">name=</span><span class="string">"product"</span> <span class="variable">column=</span><span class="string">"puuid 【自己的数据库外键列名】"</span> <span class="variable">unique=</span><span class="string">"true 【写死】"</span>/&gt;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ul>
<li><p>注解的配置 </p>
<p>  主1 【tbl_product】： </p>
  <figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@OneToOne</span>(cascade=CascadeType.ALL,mappedBy=<span class="string">"product  【对方的Java类属性名】"</span>) </span><br><span class="line"><span class="keyword">private</span> ProductInfoModel info;</span><br></pre></td></tr></table></figure>
<p>  从1 【tbl_product_info】： </p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@OneToOne</span> </span><br><span class="line"><span class="variable">@JoinColumn</span>(name=<span class="string">"puuid 【自己的数据库外键列名】"</span>) </span><br><span class="line">private ProductModel product;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="关联关系映射—1:M—联接表">关联关系映射—1:M—联接表</h4><p>标准的1:M </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+-----------+     +-----------------------+     +-----------+ </span><br><span class="line">|<span class="string">tbl_parent </span>|<span class="string">     </span>|<span class="string"> tbl_parent_child      </span>|<span class="string">     </span>|<span class="string">tbl_child  </span>|<span class="string">  </span><br><span class="line">+-----------+     +-----------------------+     +-----------+ </span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">     </span>|<span class="string"> puuid&lt;PK&gt;&lt;FK&gt;         </span>|<span class="string">     </span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string"> </span><br><span class="line">+-----------+     </span>|<span class="string"> cuuid&lt;PK&gt;&lt;FK&gt;&lt;UNIQUE&gt; </span>|<span class="string">     +-----------+ </span><br><span class="line">                  +-----------------------+</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>XML的配置<br>  1 【tbl_parent 】： </p>
  <figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;set <span class="variable">name=</span><span class="string">"children"</span> <span class="variable">table=</span><span class="string">"tbl_parent_child  【联接表】"</span>&gt; </span><br><span class="line">    &lt;key <span class="variable">column=</span><span class="string">"puuid  【联接表里代表自己的数据库列名】"</span>/&gt; </span><br><span class="line">    &lt;many-to-many <span class="variable">column=</span><span class="string">"cuuid 【联接表里代表对方的数据库列名】"</span> <span class="variable">unique=</span><span class="string">"true 【写死】"</span> <span class="variable">class=</span><span class="string">"cn.javass.model.d.ChildModel  【对方的Java类名】"</span>/&gt; </span><br><span class="line">&lt;/set&gt; </span><br><span class="line">&lt;join <span class="variable">table=</span><span class="string">"tbl_parent_child  【联接表】"</span>&gt; </span><br><span class="line">    &lt;key <span class="variable">column=</span><span class="string">"cuuid 【联接表里代表自己的数据库列名】"</span>/&gt; </span><br><span class="line">    &lt;many-to-one <span class="variable">name=</span> <span class="string">"parent"</span> <span class="variable">column=</span><span class="string">"puuid  【联接表里代表对方的数据库列名】"</span> <span class="variable">unique=</span><span class="string">"true 【写死】"</span>/&gt; </span><br><span class="line">&lt;/join&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>注解的配置<br>  1 【tbl_parent 】： </p>
  <figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@OneToMany</span>(mappedBy=<span class="string">"parent  【对方的Java类属性名】"</span>) </span><br><span class="line"><span class="keyword">private</span> Set&lt;ChildModel&gt; children = <span class="keyword">new</span> HashSet&lt;ChildModel&gt;();</span><br></pre></td></tr></table></figure>
<p>  多 【tbl_child】： </p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@ManyToOne</span> </span><br><span class="line"><span class="variable">@JoinTable</span>( </span><br><span class="line">name=<span class="string">"tbl_parent_child 【联接表】"</span>, </span><br><span class="line">joinColumns=<span class="variable">@JoinColumn</span>(name=<span class="string">"cuuid 【联接表里代表自己的数据库字段名】"</span>), </span><br><span class="line">inverseJoinColumns=<span class="variable">@JoinColumn</span>(name=<span class="string">"puuid 【联接表里代表对方的数据库字段名】"</span>) </span><br><span class="line">) </span><br><span class="line">private ParentModel parent;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="关联关系映射—1:1—联接表">关联关系映射—1:1—联接表</h4><p>标准的1:M </p>
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">+-----------+     +-----------------------+     +----------------+ </span><br><span class="line">|<span class="string">tbl_product</span>|<span class="string">     </span>|<span class="string"> tbl_product_relation  </span>|<span class="string">     </span>|<span class="string">tbl_product_info</span>|<span class="string">  </span><br><span class="line">+-----------+     +-----------------------+     +----------------+ </span><br><span class="line"></span>|<span class="string">uuid&lt;PK&gt;   </span>|<span class="string">     </span>|<span class="string"> puuid&lt;PK&gt;&lt;FK&gt;&lt;UNIQUE&gt; </span>|<span class="string">     </span>|<span class="string">uuid&lt;PK&gt;        </span>|<span class="string"> </span><br><span class="line">+-----------+     </span>|<span class="string"> cuuid&lt;PK&gt;&lt;FK&gt;&lt;UNIQUE&gt; </span>|<span class="string">     +----------------+ </span><br><span class="line">                  +-----------------------+</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>XML的配置<br>  1 【tbl_product 】： </p>
  <figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;join <span class="variable">table=</span><span class="string">"tbl_product_relation  【联接表】"</span>&gt; </span><br><span class="line">    &lt;key <span class="variable">column=</span><span class="string">"puuid  【联接表里代表自己的列名】"</span>/&gt; </span><br><span class="line">    &lt;many-to-one <span class="variable">name=</span><span class="string">"course  【自己的Java属性名】"</span> <span class="variable">column=</span><span class="string">"cuuid  【联接表里代表对方的列名】"</span> <span class="variable">unique=</span><span class="string">"true 【写死】"</span>/&gt; </span><br><span class="line">&lt;/join&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>注解的配置<br>  1 【tbl_product 】： </p>
  <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@ManyToOne</span> </span><br><span class="line"><span class="variable">@JoinTable</span>( </span><br><span class="line">name=<span class="string">"tbl_product_relation 【联接表】"</span>, </span><br><span class="line">joinColumns=<span class="variable">@JoinColumn</span>(name=<span class="string">"suuid 【联接表里代表自己的列名】"</span>), </span><br><span class="line">inverseJoinColumns=<span class="variable">@JoinColumn</span>(name=<span class="string">"cuuid 【联接表里代表对方的列名】"</span>,unique=true 【写死】) </span><br><span class="line">) </span><br><span class="line">private CourseModel course;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="二级缓存">二级缓存</h3><p>@Cache示例<br>定义在实体类上，示例如下：<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Entity</span> </span><br><span class="line"><span class="variable">@Cache</span>(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) </span><br><span class="line">public class Forest &#123; ... &#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="批量处理">批量处理</h2><p>可以使用循环进行批量处理。批量插入、更新时为了避免运行失败，定时将Session缓存的数据刷入数据库</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//累加器i是20的倍数时，将Session中的数据刷入数据库，并清空Session缓存</span></span><br><span class="line"><span class="keyword">if</span> <span class="params">(i % <span class="number">20</span> == <span class="number">0</span>)</span> &#123;</span><br><span class="line">    session.flush<span class="params">()</span>;</span><br><span class="line">    session.clear<span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>批量更新时，如果需要返回多行数据，应该使用scroll()方法，从而充分利用服务器端游标所带来的性能优势。<br><figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">Session session = HibernateUtil.currentSession<span class="params">()</span>;</span><br><span class="line">Transaction tx = session.beginTransaction<span class="params">()</span>;</span><br><span class="line">ScrollableResults users = session.createQuery<span class="params">(<span class="string">"from User"</span>)</span>.setCacheMode<span class="params">(CacheMode.IGNORE)</span>.scroll<span class="params">(ScrollMode.FORWARD_ONLY)</span>;</span><br><span class="line">int count = <span class="number">0</span>;</span><br><span class="line">while<span class="params">(users.next<span class="params">()</span>)</span>&#123;</span><br><span class="line">    User u = <span class="params">(User)</span>users.get<span class="params">(<span class="number">0</span>)</span>;</span><br><span class="line">    u.setName<span class="params">(<span class="string">"新用户"</span>)</span>;</span><br><span class="line">    <span class="keyword">if</span><span class="params">(++count % <span class="number">20</span> == <span class="number">0</span>)</span>&#123;</span><br><span class="line">        session.flush<span class="params">()</span>;</span><br><span class="line">        session.clear<span class="params">()</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">tx.commit<span class="params">()</span>;</span><br><span class="line">HibernateUtil.closeSession<span class="params">()</span>;</span><br></pre></td></tr></table></figure></p>
<p>Hibernate提供HQL语句也可以批量更新、删除。语法<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">UPDATE</span> | <span class="keyword">DELETE</span> <span class="keyword">FROM</span>? &lt;CLASSNAME&gt; [<span class="keyword">WHERE</span> WHERE_CONDITIONS]</span></span><br></pre></td></tr></table></figure></p>
<p>FROM子句中，FROM关键字是可选的。<br>在FROM子句中只能有一个类名，该类名不能有别名。<br>不能再批量HQL语句中使用连接，显式或者银石都不行。但可以在WHERE子句的语法中使用子查询。<br>整个WHERE子句是可选的。</p>
<figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">int</span> updateEntities = session.createQuery(hql).executeUpdate<span class="literal">()</span>;</span><br></pre></td></tr></table></figure>
<h2 id="使用HQL查询">使用HQL查询</h2><p>步骤</p>
<ol>
<li>获取Hibernate Session对象</li>
<li>编写HQL语句</li>
<li>以HQL语句作为参数，调用Session的createQuery方法创建查询对象。</li>
<li>如果HQL语句包含参数，则调用Query的setXXX方法为参数赋值。</li>
<li>调用Query对象的list等方法返回查询结果列表（持久化实体集）</li>
</ol>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">Session session = HibernateUtil.currentSession<span class="params">()</span>;</span><br><span class="line">Transaction tx = session.beginTransaction<span class="params">()</span>;</span><br><span class="line">SimpleDateFormat sdf = new SimpleDateFormat<span class="params">(<span class="string">"yyyy-MM-dd"</span>)</span>;</span><br><span class="line">Date start = sdf.parse<span class="params">(<span class="string">"2005-01-01"</span>)</span>;</span><br><span class="line">List pl = session.createQuery<span class="params">(<span class="string">"select distinct p from Person p"</span></span><br><span class="line">        + <span class="string">" inner join p.myEvents event where event.happenDate"</span></span><br><span class="line">        + <span class="string">" between :firstDate and :endDate"</span>)</span></span><br><span class="line">            .setDate<span class="params">(<span class="string">"firstDate"</span>, start)</span></span><br><span class="line">            .setDate<span class="params">(<span class="string">"endDate"</span>, new Date<span class="params">()</span>)</span></span><br><span class="line">            .list<span class="params">()</span>;</span><br><span class="line"><span class="keyword">for</span><span class="params">(Iterator pit = pl.iterator<span class="params">()</span>;pit.hasNext<span class="params">()</span>;)</span>&#123;</span><br><span class="line">    Person p = <span class="params">(Person)</span> pit.next<span class="params">()</span>;</span><br><span class="line">    System.out.println<span class="params">(p.getName<span class="params">()</span>)</span>;</span><br><span class="line">&#125;</span><br><span class="line">tx.commit<span class="params">()</span>;</span><br><span class="line">HibernateUtil.closeSession<span class="params">()</span>;</span><br></pre></td></tr></table></figure>
<p>执行HQL语句类似于用PreparedStatement执行SQL语句，因此HQL语句中可以使用占位符作为参数。HQL的占位符既可使用英文问好(?)，这与SQL语句中的占位符一样；也可使用有名字的占位符，使用有名字的占位符时，应该在占位符名字前增加英文冒号(:)。</p>
<p>setXXX()：方法有两个版本，分别根据参数索引赋值和根据参数名字赋值。<br>list(): 返回查询到的全部结果<br>setFirstResult(int firstResult)：设置返回的结果集从第几条开始<br>setMaxResults(int maxResults)：设置本次查询返回的结果数目</p>
<p>后两个方法用于对HQL查询实现分页控制</p>
<p>HQL语句本身是不区分大小写的。也就是说，HQL语句的关键字、函数都是不区分大小写的。但HQL语句中所使用的包名、类名、实例名、属性名都区分大小写。</p>
<h3 id="from子句">from子句</h3><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span></span><br><span class="line">from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure>
<p>建议为每个实例起别名。as关键字是可选的，为了增加可读性，建议保留。</p>
<h3 id="关联和连接">关联和连接</h3><p>两种形式关联连接：隐式和显式</p>
<p>隐式连接形式不使用join关键字，使用英文点号（.）来隐式连接关联实体，Hibernate底层自动进行关联查询。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span> p where p.myEvents.title &gt; :title</span><br></pre></td></tr></table></figure></p>
<p>显示连接则需要使用 xxx join关键字<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span> p</span><br><span class="line">inner join p.myEvents event</span><br><span class="line">where event.happenDate &lt; :endDate</span><br></pre></td></tr></table></figure></p>
<p>可使用几种连接方式</p>
<ul>
<li>inner join，内连接，可简写成join。</li>
<li>left outer join，左外连接，可简写成，left join</li>
<li>right outer join，右外连接，可简写成，right join</li>
<li>full join，全连接，不常用</li>
</ul>
<p>还可通过with关键字来提供额外的连接条件。<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">from Person <span class="tag">p</span></span><br><span class="line">inner join <span class="tag">p</span><span class="class">.myEvents</span> event</span><br><span class="line">with <span class="tag">p</span><span class="class">.id</span> &gt; event<span class="class">.id</span></span><br><span class="line">where event<span class="class">.happenDate</span> &lt; :endDate</span><br></pre></td></tr></table></figure></p>
<p>省略select关键字，返回的结果也是集合，但集合元素是被查询持久化对象、所有被关联的持久化对象所组成的数组。如上查询将会返回person、event_table表中的所有数据。</p>
<p>为了查询结果不重复可以使用distinct关键字</p>
<figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">select <span class="keyword">distinct</span> p <span class="keyword">from</span> <span class="type">Person</span> p</span><br><span class="line">inner join p.myEvents e</span><br><span class="line">where e.title := eventTitle</span><br></pre></td></tr></table></figure>
<p>如果关联实体是集合如myEvents这时不可以用隐式连接，必须显式连接关联实体或组件。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span> as p</span><br><span class="line">join fetch p.scores</span><br></pre></td></tr></table></figure></p>
<p>上次的fetch关键字将导致Hibernate在初始化Person对象时，同时抓取Person关联的scores集合属性。也可以在配置文件中制定<code>lazy=&quot;false&quot;</code></p>
<p>fetch关键字注意：</p>
<ul>
<li>fetch不应该与setMaxResults()与setFirstResult()共用。因为这些操作是基于结果集的，而在预先抓取集合类时可能包含重复的数据，即无法预先知道精确的行数。</li>
<li>fetch不能与独立的with条件一起使用</li>
<li>如果在一次查询中fetch多个集合，可以查询返回笛卡尔积，因此要多加注意。</li>
<li>对bag映射而言，同时join fetch多个集合时可能出现非预期结果，因此需要谨慎使用。</li>
<li>full join fetch 与 right join fetch是没有任何意义的</li>
</ul>
<p>也可以通过fetch all properties 来强制Hibernate立即抓取这些属性。<br><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Document fetch all properties order <span class="keyword">by</span> <span class="property">name</span></span><br></pre></td></tr></table></figure></p>
<h3 id="select子句">select子句</h3><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select p.name.firstName from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure>
<p>select可以选择组件属性包含的属性<br>通常情况下，使用select子句查询的结果是集合，而集合元素是select后的实例、属性等组成的数组。<br>如果select后只有一项（包括持久化实例或属性），则查询得到的集合元素就是该持久化实例或属性。<br>如果select后有多个项，则每个集合元素就是选择出的多项组成的数组。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select p.name, p from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure></p>
<p>集合元素类似于[String,Person]结构的数组，其中第一个元素是Person实例的name属性，第二个是Person实例</p>
<p>将选出的属性存入一个List对象。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select new list(p.name,p.address) from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure></p>
<p>返回的集合元素是list而不是数组<br>也可以将选出的属性封装为对象，必须有对应的构造方法<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select new ClassTest(p.name,p.address) from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure></p>
<p>还可以给选出元素命名别名<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select p.name as personName from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure></p>
<p>这种用法与new map结合使用更加普遍。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select new map(p.name as personName) from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure></p>
<p>选出的集合元素是Map对象，以personName作为Map的key，实际选出的值作为Map的value</p>
<h3 id="HQL查询的聚集函数">HQL查询的聚集函数</h3><ul>
<li>avg：计算属性平均值</li>
<li>count：统计选择对象的数量</li>
<li>max：统计属性值的最大值</li>
<li>min：统计属性值的最小值</li>
<li>sum：计算属性值的总和</li>
</ul>
<p>select子句还支持字符串连接符、算术运算符，以及SQL函数。也支持使用distinct和all关键字。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select p.name || <span class="string">""</span> || p.address from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure></p>
<h3 id="多态查询">多态查询</h3><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span> as p</span><br></pre></td></tr></table></figure>
<p>该查询语句不仅会查出Person的全部实例，还会查询出Person的子类。<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from java<span class="class">.lang</span><span class="class">.Object</span> o</span><br></pre></td></tr></table></figure></p>
<p>该查询可以返回所有被持久化的对象。此查询无法使用order by子句对结果集排序，从而不允许对这些查询结果使用Query.scroll()</p>
<h3 id="HQL查询的where子句">HQL查询的where子句</h3><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Cat cat <span class="keyword">where</span> cat.mate.<span class="property">name</span> like <span class="string">"kit%"</span></span><br></pre></td></tr></table></figure>
<p>如果cat.mate是集合属性，Hibernate3.2.3以后的版本不支持这种用法。<br>class关键字用来存取一个实例的鉴别值。嵌入where子句中的java类名，将被作为该类的鉴别值。<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Cat</span> <span class="keyword">cat</span> where <span class="keyword">cat</span>.<span class="keyword">class</span> = DomesticCat</span><br></pre></td></tr></table></figure></p>
<p>当where子句的运算符只支持基本类型或字符串时，where子句中的属性表达式必须以基本类型或者字符串结尾，不要使用组件类型属性结尾。<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from Account as a where a.<span class="keyword">person</span>.name.firstName like <span class="string">"dd%"</span></span><br></pre></td></tr></table></figure></p>
<p>下面的语句则是错误的<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from Account as a where a.<span class="keyword">person</span>.name like <span class="string">"dd%"</span></span><br></pre></td></tr></table></figure></p>
<p>‘=’可以用于实例。</p>
<h3 id="表达式">表达式</h3><p>在where子句中允许使用的表达式包括 大多数你可以在SQL使用的表达式种类:</p>
<ul>
<li>数学运算符<code>+, -, *, /</code></li>
<li>二进制比较运算符<code>=, &gt;=, &lt;=, &lt;&gt;, !=, like</code></li>
<li>逻辑运算符<code>and, or, not</code></li>
<li>in, not in, between, is null, is not null, is empty, is not empty, member of and not member of</li>
<li>“简单的” case, case … when … then … else … end,和 “搜索” case, case when … then … else … end</li>
<li>字符串连接符…||… or concat(…,…)</li>
<li>current_date(), current_time(), current_timestamp()</li>
<li>second(…), minute(…), hour(…), day(…), month(…), year(…),</li>
<li>EJB-QL 3.0定义的任何函数或操作：substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length()</li>
<li>coalesce() 和 nullif()</li>
<li>cast(… as …), 其第二个参数是某Hibernate类型的名字，以及extract(… from …)，只要ANSI cast() 和 extract() 被底层数据库支持</li>
<li>任何数据库支持的SQL标量函数，比如sign(), trunc(), rtrim(), sin()</li>
<li>JDBC参数传入 ?</li>
<li>命名参数:name, :start_date, :x1</li>
<li>SQL 直接常量 ‘foo’, 69, ‘1970-01-01 10:00:01.0’</li>
<li><p>Java public static final 类型的常量 eg.Color.TABBY</p>
</li>
<li><p>关键字in与between可按如下方法使用:</p>
  <figure class="highlight oxygene"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> DomesticCat cat <span class="keyword">where</span> cat.name between <span class="string">'A'</span> <span class="keyword">and</span> <span class="string">'B'</span></span><br><span class="line"><span class="keyword">from</span> DomesticCat cat <span class="keyword">where</span> cat.name <span class="keyword">in</span> ( <span class="string">'Foo'</span>, <span class="string">'Bar'</span>, <span class="string">'Baz'</span> )</span><br></pre></td></tr></table></figure></li>
<li><p>而且否定的格式也可以如下书写：</p>
  <figure class="highlight oxygene"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> DomesticCat cat <span class="keyword">where</span> cat.name <span class="keyword">not</span> between <span class="string">'A'</span> <span class="keyword">and</span> <span class="string">'B'</span></span><br><span class="line"><span class="keyword">from</span> DomesticCat cat <span class="keyword">where</span> cat.name <span class="keyword">not</span> <span class="keyword">in</span> ( <span class="string">'Foo'</span>, <span class="string">'Bar'</span>, <span class="string">'Baz'</span> )</span><br></pre></td></tr></table></figure>
</li>
<li><p>同样, 子句is null与is not null可以被用来测试空值(null).</p>
</li>
<li><p>在Hibernate配置文件中声明HQL“查询替代（query substitutions）”之后， 布尔表达式（Booleans）可以在其他表达式中轻松的使用:</p>
  <figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="keyword">property</span> <span class="property">name</span>=<span class="string">"hibernate.query.substitutions"</span>&gt;<span class="constant">true</span> <span class="number">1</span>, <span class="constant">false</span> <span class="number">0</span>&lt;/<span class="keyword">property</span>&gt;</span><br></pre></td></tr></table></figure>
<p>  系统将该HQL转换为SQL语句时，该设置表明将用字符 1 和 0 来 取代关键字true 和 false:</p>
  <figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Cat cat <span class="keyword">where</span> cat.alive = <span class="constant">true</span></span><br></pre></td></tr></table></figure></li>
<li>你可以用特殊属性size, 或是特殊函数size()测试一个集合的大小。  <figure class="highlight matlab"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from Cat <span class="built_in">cat</span> where <span class="built_in">cat</span>.kittens.<span class="built_in">size</span> &gt; <span class="number">0</span></span><br><span class="line">from Cat <span class="built_in">cat</span> where <span class="built_in">size</span>(<span class="built_in">cat</span>.kittens) &gt; <span class="number">0</span></span><br></pre></td></tr></table></figure></li>
<li>对于索引了（有序）的集合，你可以使用minindex 与 maxindex函数来引用到最小与最大的索引序数。 同理，你可以使用minelement 与 maxelement函数来 引用到一个基本数据类型的集合中最小与最大的元素。  <figure class="highlight vbnet"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Calendar cal <span class="keyword">where</span> maxelement(cal.holidays) &gt; current <span class="built_in">date</span></span><br><span class="line"><span class="keyword">from</span> <span class="keyword">Order</span> <span class="keyword">order</span> <span class="keyword">where</span> maxindex(<span class="keyword">order</span>.items) &gt; <span class="number">100</span></span><br><span class="line"><span class="keyword">from</span> <span class="keyword">Order</span> <span class="keyword">order</span> <span class="keyword">where</span> minelement(<span class="keyword">order</span>.items) &gt; <span class="number">10000</span></span><br></pre></td></tr></table></figure></li>
<li><p>在传递一个集合的索引集或者是元素集(elements与indices 函数) 或者传递一个子查询的结果的时候，可以使用SQL函数any, some, all, exists, in</p>
  <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">select mother from Cat as mother, Cat as kit</span><br><span class="line">where kit <span class="keyword">in</span> <span class="function"><span class="title">elements</span><span class="params">(foo.kittens)</span></span></span><br><span class="line">select <span class="tag">p</span> from NameList list, Person <span class="tag">p</span></span><br><span class="line">where <span class="tag">p</span><span class="class">.name</span> = some <span class="function"><span class="title">elements</span><span class="params">(list.names)</span></span></span><br><span class="line">from Cat cat where exists <span class="function"><span class="title">elements</span><span class="params">(cat.kittens)</span></span></span><br><span class="line">from Player <span class="tag">p</span> where <span class="number">3</span> &gt; all <span class="function"><span class="title">elements</span><span class="params">(p.scores)</span></span></span><br><span class="line">from Show show where <span class="string">'fizard'</span> <span class="keyword">in</span> <span class="function"><span class="title">indices</span><span class="params">(show.acts)</span></span></span><br></pre></td></tr></table></figure>
<p>  注意，在Hibernate3种，这些结构变量- size, elements, indices, minindex, maxindex, minelement, maxelement - 只能在where子句中使用。</p>
</li>
<li><p>一个被索引过的（有序的）集合的元素(arrays, lists, maps)可以在其他索引中被引用（只能在where子句中）：</p>
  <figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">from Order order where order.items<span class="comment">[0]</span>.id = 1234</span><br><span class="line">select <span class="keyword">person</span> from <span class="keyword">Person</span> <span class="keyword">person</span>, Calendar calendar</span><br><span class="line">where calendar.holidays<span class="comment">['national day']</span> = <span class="keyword">person</span>.birthDay</span><br><span class="line">    and <span class="keyword">person</span>.nationality.calendar = calendar</span><br><span class="line">select item from Item item, Order order</span><br><span class="line">where order.items<span class="comment">[ order.deliveredItemIndices<span class="comment">[0]</span> ]</span> = item and order.id = 11</span><br><span class="line">select item from Item item, Order order</span><br><span class="line">where order.items<span class="comment">[ maxindex(order.items) ]</span> = item and order.id = 11</span><br></pre></td></tr></table></figure>
<p>  在[]中的表达式甚至可以是一个算数表达式。</p>
  <figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">select</span> item <span class="keyword">from</span> Item item, <span class="keyword">Order</span> <span class="keyword">order</span></span><br><span class="line"><span class="keyword">where</span> <span class="keyword">order</span>.items[ <span class="keyword">size</span>(<span class="keyword">order</span>.items) - <span class="number">1</span> ] = item</span></span><br></pre></td></tr></table></figure>
<p>  对于一个一对多的关联（one-to-many association）或是值的集合中的元素， HQL也提供内建的index()函数，</p>
  <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">select item, <span class="function"><span class="title">index</span><span class="params">(item)</span></span> from Order <span class="attribute">order</span> </span><br><span class="line">    join <span class="attribute">order</span><span class="class">.items</span> item</span><br><span class="line">where <span class="function"><span class="title">index</span><span class="params">(item)</span></span> &lt; <span class="number">5</span></span><br></pre></td></tr></table></figure>
<p>  如果底层数据库支持标量的SQL函数，它们也可以被使用</p>
  <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from DomesticCat cat where <span class="function"><span class="title">upper</span><span class="params">(cat.name)</span></span> like <span class="string">'FRI%'</span></span><br></pre></td></tr></table></figure>
<p>  如果你还不能对所有的这些深信不疑，想想下面的查询。如果使用SQL，语句长度会增长多少，可读性会下降多少：</p>
  <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">select cust</span><br><span class="line">from Product prod,</span><br><span class="line">    Store store</span><br><span class="line">    inner join store<span class="class">.customers</span> cust</span><br><span class="line">where prod<span class="class">.name</span> = <span class="string">'widget'</span></span><br><span class="line">    and store<span class="class">.location</span><span class="class">.name</span> <span class="keyword">in</span> ( <span class="string">'Melbourne'</span>, <span class="string">'Sydney'</span> )</span><br><span class="line">    and prod = all <span class="function"><span class="title">elements</span><span class="params">(cust.currentOrder.lineItems)</span></span></span><br></pre></td></tr></table></figure>
<p>  提示: 会像如下的语句</p>
  <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">SELECT cust<span class="class">.name</span>, cust<span class="class">.address</span>, cust<span class="class">.phone</span>, cust<span class="class">.id</span>, cust<span class="class">.current_order</span></span><br><span class="line">FROM customers cust,</span><br><span class="line">    stores store,</span><br><span class="line">    locations loc,</span><br><span class="line">    store_customers sc,</span><br><span class="line">    product prod</span><br><span class="line">WHERE prod<span class="class">.name</span> = <span class="string">'widget'</span></span><br><span class="line">    AND store<span class="class">.loc_id</span> = loc<span class="class">.id</span></span><br><span class="line">    AND loc<span class="class">.name</span> IN ( <span class="string">'Melbourne'</span>, <span class="string">'Sydney'</span> )</span><br><span class="line">    AND sc<span class="class">.store_id</span> = store<span class="class">.id</span></span><br><span class="line">    AND sc<span class="class">.cust_id</span> = cust<span class="class">.id</span></span><br><span class="line">    AND prod<span class="class">.id</span> = ALL(</span><br><span class="line">        SELECT item<span class="class">.prod_id</span></span><br><span class="line">        FROM line_items item, orders o</span><br><span class="line">        WHERE item<span class="class">.order_id</span> = o<span class="class">.id</span></span><br><span class="line">            AND cust<span class="class">.current_order</span> = o<span class="class">.id</span></span><br><span class="line">    )</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="order_by子句">order by子句</h3><p>查询返回的列表(list)可以按照一个返回的类或组件（components)中的任何属性（property）进行排序：<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from DomesticCat <span class="keyword">cat</span></span><br><span class="line"><span class="keyword">order</span> <span class="keyword">by</span> <span class="keyword">cat</span>.name asc, <span class="keyword">cat</span>.weight <span class="keyword">desc</span>, <span class="keyword">cat</span>.birthdate</span><br></pre></td></tr></table></figure></p>
<p>可选的asc或desc关键字指明了按照升序或降序进行排序.默认是升序排序。</p>
<h3 id="group_by子句">group by子句</h3><p>一个返回聚集值(aggregate values)的查询可以按照一个返回的类或组件（components)中的任何属性（property）进行分组：</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">select cat<span class="class">.color</span>, <span class="function"><span class="title">sum</span><span class="params">(cat.weight)</span></span>, <span class="function"><span class="title">count</span><span class="params">(cat)</span></span> </span><br><span class="line">from Cat cat</span><br><span class="line">group by cat<span class="class">.color</span></span><br><span class="line">select foo<span class="class">.id</span>, <span class="function"><span class="title">avg</span><span class="params">(name)</span></span>, <span class="function"><span class="title">max</span><span class="params">(name)</span></span> </span><br><span class="line">from Foo foo join foo<span class="class">.names</span> name</span><br><span class="line">group by foo.id</span><br></pre></td></tr></table></figure>
<p>having子句在这里也允许使用.</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">select cat<span class="class">.color</span>, <span class="function"><span class="title">sum</span><span class="params">(cat.weight)</span></span>, <span class="function"><span class="title">count</span><span class="params">(cat)</span></span> </span><br><span class="line">from Cat cat</span><br><span class="line">group by cat<span class="class">.color</span> </span><br><span class="line">having cat<span class="class">.color</span> <span class="keyword">in</span> (eg<span class="class">.Color</span><span class="class">.TABBY</span>, eg<span class="class">.Color</span><span class="class">.BLACK</span>)</span><br></pre></td></tr></table></figure>
<p>如果底层的数据库支持的话(例如不能在MySQL中使用)，SQL的一般函数与聚集函数也可以出现 在having与order by 子句中。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">select</span> cat</span><br><span class="line"><span class="keyword">from</span> Cat cat</span><br><span class="line">    <span class="keyword">join</span> cat.kittens kitten</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> cat</span><br><span class="line"><span class="keyword">having</span> <span class="keyword">avg</span>(kitten.weight) &gt; <span class="number">100</span></span><br><span class="line"><span class="keyword">order</span> <span class="keyword">by</span> <span class="keyword">count</span>(kitten) <span class="keyword">asc</span>, <span class="keyword">sum</span>(kitten.weight) <span class="keyword">desc</span></span></span><br></pre></td></tr></table></figure>
<p>注意group by子句与 order by子句中都不能包含算术表达式（arithmetic expressions）.</p>
<h3 id="子查询">子查询</h3><p>对于支持子查询的数据库，Hibernate支持在查询中使用子查询。一个子查询必须被圆括号包围起来（经常是SQL聚集函数的圆括号）。 甚至相互关联的子查询（引用到外部查询中的别名的子查询）也是允许的。<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Cat <span class="keyword">as</span> fatcat </span><br><span class="line"><span class="keyword">where</span> fatcat.weight &gt; ( </span><br><span class="line">    <span class="function"><span class="keyword">select</span> <span class="title">avg</span>(<span class="params">cat.weight</span>) <span class="keyword">from</span> DomesticCat cat </span><br><span class="line">)</span></span><br></pre></td></tr></table></figure></p>
<p>在select列表中包含一个表达式以上的子查询，你可以使用一个元组构造符（tuple constructors）：<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Cat</span> <span class="keyword">as</span> <span class="keyword">cat</span> </span><br><span class="line">where not ( <span class="keyword">cat</span>.name, <span class="keyword">cat</span>.color ) <span class="keyword">in</span> ( </span><br><span class="line">    select <span class="keyword">cat</span>.name, <span class="keyword">cat</span>.color from DomesticCat <span class="keyword">cat</span> </span><br><span class="line">)</span><br></pre></td></tr></table></figure></p>
<p>注意在某些数据库中（不包括Oracle与HSQL），你也可以在其他语境中使用元组构造符， 比如查询用户类型的组件与组合：</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span> where name = ('Gavin', 'A', 'King')</span><br></pre></td></tr></table></figure>
<p>该查询等价于更复杂的：</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">from <span class="keyword">Person</span> where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')</span><br></pre></td></tr></table></figure>
<p>有两个很好的理由使你不应当作这样的事情：首先，它不完全适用于各个数据库平台；其次，查询现在依赖于映射文件中属性的顺序。</p>
<h3 id="命名查询">命名查询</h3><p>命名查询实际上就是给查询语句起个名字，执行查询的时候就是直接使用起的这个名字，避免重复写HQL语句，使查询在代码中得到更多的重用。</p>
<ol>
<li><p>使用@NamedQuery注解在实体类中定义命名查询。</p>
 <figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@<span class="function"><span class="title">NamedQuery</span><span class="params">(name=<span class="string">"findAllUser"</span>,query=<span class="string">"SELECT u FROM User u"</span>)</span></span></span><br></pre></td></tr></table></figure>
<p> @NamedQuery中的属性name指定命名查询的名称，query属性指定命名查询的语句。</p>
<p> 如果要定义多个命名查询，需要使用@NamedQueries。</p>
 <figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@NamedQueries</span>(&#123;</span><br><span class="line">    <span class="variable">@NamedQuery</span>(name=<span class="string">"findAllUser"</span>,query=<span class="string">"SELECT u FROM User u"</span>),</span><br><span class="line">    <span class="variable">@NamedQuery</span>(name=<span class="string">"findUserWithId"</span>,query=<span class="string">"SELECT u FROM User u WHERE u.id = ?1"</span>),</span><br><span class="line">    <span class="variable">@NamedQuery</span>(name=<span class="string">"findUserWithName"</span>,query=<span class="string">"SELECT u FROM User u WHERE u.name = :name"</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
</li>
<li><p>定义好命名查询后，可以使用EntityManager的createNamedQuery方法传入命名查询的名称创建查询。例如：createNamedQuery(“findAllUser”);</p>
</li>
<li>一个简单的例子。　　</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> entity;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.Column;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.Entity;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.GeneratedValue;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.Id;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.NamedQueries;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.NamedQuery;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.Table;</span><br><span class="line"> </span><br><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@Table</span>(name=<span class="string">"t_user"</span>)</span><br><span class="line"><span class="annotation">@NamedQueries</span>(&#123;</span><br><span class="line">        <span class="annotation">@NamedQuery</span>(name=<span class="string">"findAllUser"</span>,query=<span class="string">"SELECT u FROM User u"</span>),</span><br><span class="line">        <span class="annotation">@NamedQuery</span>(name=<span class="string">"findUserWithId"</span>,query=<span class="string">"SELECT u FROM User u WHERE u.id = ?1"</span>),</span><br><span class="line">        <span class="annotation">@NamedQuery</span>(name=<span class="string">"findUserWithName"</span>,query=<span class="string">"SELECT u FROM User u WHERE u.name = :name"</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="annotation">@Id</span></span><br><span class="line">    <span class="annotation">@GeneratedValue</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">     </span><br><span class="line">    <span class="annotation">@Column</span>(name=<span class="string">"name"</span>)</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">     </span><br><span class="line">    <span class="function"><span class="keyword">public</span> Long <span class="title">getId</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> id; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setId</span><span class="params">(Long id)</span> </span>&#123; <span class="keyword">this</span>.id = id; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> name; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123; <span class="keyword">this</span>.name = name; &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>测试<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.EntityManager;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.EntityManagerFactory;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.Persistence;</span><br><span class="line"><span class="keyword">import</span> javax.persistence.Query;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> org.junit.After;</span><br><span class="line"><span class="keyword">import</span> org.junit.Before;</span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> entity.User;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestNamedQuery</span> </span>&#123;</span><br><span class="line">     </span><br><span class="line">    EntityManagerFactory emf = <span class="keyword">null</span>;</span><br><span class="line">     </span><br><span class="line">    <span class="annotation">@Before</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">before</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//根据在persistence.xml中配置的persistence-unit name 创建EntityManagerFactory</span></span><br><span class="line">        emf = Persistence.createEntityManagerFactory(<span class="string">"myJPA"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">     </span><br><span class="line">    <span class="annotation">@After</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">after</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//关闭EntityManagerFactory</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> != emf) &#123;</span><br><span class="line">            emf.close();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">     </span><br><span class="line">    <span class="annotation">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testNamedQuery1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        EntityManager em = emf.createEntityManager();</span><br><span class="line">        List&lt;User&gt; users = em.createNamedQuery(<span class="string">"findAllUser"</span>).getResultList();<span class="comment">//根据User实体中定义的命名查询</span></span><br><span class="line">    &#125;</span><br><span class="line">     </span><br><span class="line">    <span class="annotation">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testNamedQuery2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        EntityManager em = emf.createEntityManager();</span><br><span class="line">        Query query =  em.createNamedQuery(<span class="string">"findUserWithId"</span>);<span class="comment">//根据User实体中定义的命名查询</span></span><br><span class="line">        query.setParameter(<span class="number">1</span>, <span class="number">2L</span>);</span><br><span class="line">        List&lt;User&gt; users = query.getResultList();</span><br><span class="line">    &#125;</span><br><span class="line">     </span><br><span class="line">    <span class="annotation">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testNamedQuery3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        EntityManager em = emf.createEntityManager();</span><br><span class="line">        Query query =  em.createNamedQuery(<span class="string">"findUserWithName"</span>);<span class="comment">//根据User实体中定义的命名查询</span></span><br><span class="line">        query.setParameter(<span class="string">"name"</span>, <span class="string">"李坏"</span>);</span><br><span class="line">        List&lt;User&gt; users = query.getResultList();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="条件查询">条件查询</h2><ul>
<li>Criteria：代表一次查询</li>
<li>Criterion：代表一个查询条件</li>
<li>Restrictions：产生查询条件的工具类</li>
</ul>
<p>执行条件查询的步骤如下：</p>
<ol>
<li>获得Hibernate的Session对象</li>
<li>以Session对象创建Criteria （org.hibernate.Criteria接口表示特定持久类的一个查询。Session是 Criteria实例的工厂。）</li>
<li>使用Restrictions的静态方法创建Criterion查询条件</li>
<li>向Criteria查询中添加Criterion查询条件</li>
<li>执行Criteria的list等方法返回结果集</li>
</ol>
<figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">List</span> <span class="built_in">list</span> <span class="subst">=</span> session<span class="built_in">.</span>createCriteria(Student<span class="built_in">.</span>class)</span><br><span class="line"><span class="built_in">.</span>add(Restrictions<span class="built_in">.</span><span class="literal">gt</span>(<span class="string">"name"</span>,<span class="string">"a"</span>))</span><br><span class="line"><span class="built_in">.</span><span class="built_in">list</span>();</span><br></pre></td></tr></table></figure>
<p>Criteria常用方法</p>
<ul>
<li>Criteria setFirstResult(int firstResult):设置查询返回的第一行记录</li>
<li>Criteria setMaxResults(int maxResults):设置查询返回的记录数</li>
<li>Criteria add(Criterion criterion):增加查询条件</li>
<li>Criteria addOrder(Order order):增加排序规则</li>
</ul>
<p>Restrictions产生查询条件Criterion，常用静态方法</p>
<p>下面方法返回Criterion</p>
<ul>
<li>Restrictions.eq —&gt; equal,等于.</li>
<li>Restrictions.allEq —&gt; 参数为Map对象,使用key/value进行多个等于的比对,相当于多个Restrictions.eq的效果</li>
<li>Restrictions.gt —&gt; great-than &gt; 大于</li>
<li>Restrictions.ge —&gt; great-equal &gt;= 大于等于</li>
<li>Restrictions.lt —&gt; less-than, &lt; 小于</li>
<li>Restrictions.le —&gt; less-equal &lt;= 小于等于</li>
<li>Restrictions.between —&gt; 对应SQL的between子句</li>
<li>Restrictions.like —&gt; 对应SQL的LIKE子句</li>
<li>Restrictions.in —&gt; 对应SQL的in子句</li>
<li>Restrictions.and —&gt; and 关系</li>
<li>Restrictions.or —&gt; or 关系</li>
<li>Restrictions.not —&gt; 求否</li>
<li>Restrictions.isEmpty —&gt; 判断属性是否为空,为空则返回true</li>
<li>Restrictions.isNotEmpty —&gt; 与isNull相反</li>
<li>Restrictions.isNull —&gt; 判断属性是否为空,为空则返回true</li>
<li>Restrictions.isNotNull —&gt; 与isNull相反</li>
<li>Restrictions.sqlRestriction —&gt; SQL限定的查询</li>
<li>Restrictions.sizeEq —&gt; 判断某个属性的元素个数是否与size相等<br>下面方法返回Order</li>
<li>Restrictions.asc —&gt; 限定升序排序</li>
<li>Restrictions.desc —&gt; 限定降序排序</li>
</ul>
<h3 id="关联和动态关联">关联和动态关联</h3><p>你可以使用createCriteria()非常容易的在互相关联的实体间建立约束。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">List list = session.createCriteria<span class="params">(Student.class)</span></span><br><span class="line">    .add<span class="params">( Restrictions.like<span class="params">(<span class="string">"name"</span>, <span class="string">"F%"</span>)</span></span><br><span class="line">    .createCriteria<span class="params">(<span class="string">"enrolments"</span>)</span></span><br><span class="line">    .add<span class="params">( Restrictions.gt<span class="params">(<span class="string">"semester"</span>, <span class="number">2</span>)</span></span><br><span class="line">    .list<span class="params">()</span>;</span></span></span><br></pre></td></tr></table></figure>
<p>第一个查询条件是直接过滤Person的属性。第二个查询条件则过滤Person的关联实体的属性，其中enrolments是Person类的关联实体，而semester则是Enrolment类的属性。返回的并不是Enrolment对象，而是Person对象的集合。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">List list = session.createCriteria<span class="params">(Student.class)</span></span><br><span class="line">    .add<span class="params">( Restrictions.like<span class="params">(<span class="string">"name"</span>, <span class="string">"F%"</span>)</span></span><br><span class="line">    .createAlias<span class="params">(<span class="string">"enrolments"</span>,<span class="string">"en"</span>)</span></span><br><span class="line">    .add<span class="params">( Restrictions.gt<span class="params">(<span class="string">"en.semester"</span>, <span class="number">2</span>)</span></span><br><span class="line">    .list<span class="params">()</span>;</span></span></span><br></pre></td></tr></table></figure>
<p>createAlias()并不创建一个新的 Criteria实例。它只是给关联实体（包括集合里包含的关联实体）起一个别名，让后面的过滤条件可根据该关联实体进行筛选。</p>
<p>Student实例所保存的之前两次查询所返回的enrolments集合是没有被条件预过滤的。如果你希望只获得符合条件的enrolments， 你必须使用returnMaps()。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">List list = session.createCriteria<span class="params">(Student.class)</span></span><br><span class="line">    .add<span class="params">( Restrictions.like<span class="params">(<span class="string">"name"</span>, <span class="string">"F%"</span>)</span></span><br><span class="line">    .createCriteria<span class="params">(<span class="string">"enrolments"</span>,<span class="string">"en"</span>)</span></span><br><span class="line">    .add<span class="params">( Restrictions.gt<span class="params">(<span class="string">"en.semester"</span>, <span class="number">2</span>)</span></span><br><span class="line">    .returnMaps<span class="params">()</span></span><br><span class="line">    .list<span class="params">()</span>;</span><br><span class="line">Iterator iter = list.iterator<span class="params">()</span>;</span><br><span class="line">while <span class="params">( iter.hasNext<span class="params">()</span> )</span> &#123;</span><br><span class="line">    Map map = <span class="params">(Map)</span> iter.next<span class="params">()</span>;</span><br><span class="line">    Student stu= <span class="params">(Student)</span> map.get<span class="params">(Criteria.ROOT_ALIAS)</span>;</span><br><span class="line">    Student en = <span class="params">(Student)</span> map.get<span class="params">(<span class="string">"en"</span>)</span>;</span><br><span class="line">&#125;</span></span></span><br></pre></td></tr></table></figure>
<p><strong>动态关联抓取</strong></p>
<p>FetchMode里有如下几个常量：</p>
<ul>
<li>DEFAULT：使用配置文件指定的延迟加载策略处理</li>
<li>JOIN：使用外连接、预初始化所有关联实体</li>
<li>SELECT：启用延迟加载，系统将使用单独的select语句来初始化关联实体。只有当真正访问关联实体的时候，才会执行第二条select语句。</li>
</ul>
<p>你可以使用setFetchMode()在运行时定义动态关联抓取的语义。</p>
<figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">List</span> <span class="built_in">list</span> <span class="subst">=</span> session<span class="built_in">.</span>createCriteria(Student<span class="built_in">.</span>class)</span><br><span class="line">    <span class="built_in">.</span>add( Restrictions<span class="built_in">.</span>like(<span class="string">"name"</span>, <span class="string">"F%"</span>)</span><br><span class="line">    <span class="built_in">.</span>setFetchMode(<span class="string">"enrolments"</span>,FetchMode<span class="built_in">.</span><span class="keyword">JOIN</span>)</span><br><span class="line">    <span class="built_in">.</span><span class="built_in">list</span>();</span><br></pre></td></tr></table></figure>
<p>以上程序会预初始化Student关联的enrolments集合。</p>
<h3 id="投影(Projections)、聚合（aggregation）和分组（grouping）">投影(Projections)、聚合（aggregation）和分组（grouping）</h3><p>org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用 setProjection()应用投影到一个查询。</p>
<ul>
<li>AggregateProjection avg(String propertyName)：类似avg函数</li>
<li>CountProjection count(String propertyName)：类似count函数</li>
<li>CountProjection countDistinct(String propertyName)：类似count(distinct column)</li>
<li>PropertyProjection groupProperty(String propertyName)：类似添加group by子句</li>
<li>AggregateProjection max(String propertyName)：类似max函数</li>
<li>AggregateProjection min(String propertyName)：类似min函数</li>
<li>Projection rowCount()：类似count(*)</li>
<li>AggregateProjection sum(String propertyName)：类似sum函数</li>
</ul>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">List results = session.createCriteria<span class="params">(Cat.class)</span></span><br><span class="line">    .setProjection<span class="params">( Projections.rowCount<span class="params">()</span> )</span></span><br><span class="line">    .add<span class="params">( Restrictions.eq<span class="params">(<span class="string">"color"</span>, Color.BLACK)</span> )</span></span><br><span class="line">    .list<span class="params">()</span>;</span><br><span class="line">List results = session.createCriteria<span class="params">(Cat.class)</span></span><br><span class="line">    .setProjection<span class="params">( Projections.projectionList<span class="params">()</span></span><br><span class="line">        .add<span class="params">( Projections.rowCount<span class="params">()</span> )</span></span><br><span class="line">        .add<span class="params">( Projections.avg<span class="params">(<span class="string">"weight"</span>)</span> )</span></span><br><span class="line">        .add<span class="params">( Projections.max<span class="params">(<span class="string">"weight"</span>)</span> )</span></span><br><span class="line">        .add<span class="params">( Projections.groupProperty<span class="params">(<span class="string">"color"</span>)</span> )</span></span><br><span class="line">    )</span></span><br><span class="line">    .list<span class="params">()</span>;</span><br></pre></td></tr></table></figure>
<p>在一个条件查询中没有必要显式的使用 “group by” 。某些投影类型就是被定义为 分组投影，他们也出现在SQL的group by子句中。</p>
<p>你可以选择把一个别名指派给一个投影，这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式：<br><figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">List results = session.createCriteria<span class="params">(Cat.class)</span></span><br><span class="line">    .setProjection<span class="params">( Projections.alias<span class="params">( Projections.groupProperty<span class="params">(<span class="string">"color"</span>)</span>, <span class="string">"colr"</span> )</span> )</span></span><br><span class="line">    .addOrder<span class="params">( Order.asc<span class="params">(<span class="string">"colr"</span>)</span> )</span></span><br><span class="line">    .list<span class="params">()</span>;</span><br><span class="line">List results = session.createCriteria<span class="params">(Cat.class)</span></span><br><span class="line">    .setProjection<span class="params">( Projections.groupProperty<span class="params">(<span class="string">"color"</span>)</span>.as<span class="params">(<span class="string">"colr"</span>)</span> )</span></span><br><span class="line">    .addOrder<span class="params">( Order.asc<span class="params">(<span class="string">"colr"</span>)</span> )</span></span><br><span class="line">    .list<span class="params">()</span>;</span><br></pre></td></tr></table></figure></p>
<p>alias()和as()方法简便的将一个投影实例包装到另外一个别名的Projection实例中。简而言之，当你添加一个投影到一个投影列表中时你可以为它指定一个别名，使用ProjectionList的add()方法添加投影时指定别名</p>
<h3 id="离线(detached)查询和子查询">离线(detached)查询和子查询</h3><p>DetachedCriteria类使你在一个session范围之外创建一个查询，并且可以使用任意的 Session来执行它。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">DetachedCriteria query = DetachedCriteria.forClass<span class="params">(Cat.class)</span></span><br><span class="line">    .add<span class="params">( Property.forName<span class="params">(<span class="string">"sex"</span>)</span>.eq<span class="params">('F')</span> )</span>;</span><br><span class="line">Session session = HibernateUtil.currentSession<span class="params">()</span>; </span><br><span class="line">Transaction txn = session.beginTransaction<span class="params">()</span>;</span><br><span class="line">List results = query.getExecutableCriteria<span class="params">(session)</span>.setMaxResults<span class="params">(<span class="number">100</span>)</span>.list<span class="params">()</span>;</span><br><span class="line">txn.commit<span class="params">()</span>;</span><br><span class="line">session.close<span class="params">()</span>;</span><br></pre></td></tr></table></figure>
<p>DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者Property获得。</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">DetachedCriteria avgWeight = DetachedCriteria.forClass(<span class="keyword">Cat</span>.<span class="keyword">class</span>)</span><br><span class="line">	.setProjection( Property.forName(<span class="string">"weight"</span>).avg() );</span><br><span class="line">session.createCriteria(<span class="keyword">Cat</span>.<span class="keyword">class</span>)</span><br><span class="line">	.add( Property.forName("weight).gt(avgWeight) )</span><br><span class="line">	.<span class="keyword">list</span>();</span><br><span class="line">DetachedCriteria weights = DetachedCriteria.forClass(<span class="keyword">Cat</span>.<span class="keyword">class</span>)</span><br><span class="line">	.setProjection( Property.forName(<span class="string">"weight"</span>) );</span><br><span class="line">session.createCriteria(<span class="keyword">Cat</span>.<span class="keyword">class</span>)</span><br><span class="line">	.add( Subqueries.geAll(<span class="string">"weight"</span>, weights) )</span><br><span class="line">	.<span class="keyword">list</span>();</span><br></pre></td></tr></table></figure>
<p>甚至相互关联的子查询也是有可能的：</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">DetachedCriteria avgWeightForSex = DetachedCriteria.forClass<span class="params">(Cat.class, <span class="string">"cat2"</span>)</span></span><br><span class="line">	.setProjection<span class="params">( Property.forName<span class="params">(<span class="string">"weight"</span>)</span>.avg<span class="params">()</span> )</span></span><br><span class="line">	.add<span class="params">( Property.forName<span class="params">(<span class="string">"cat2.sex"</span>)</span>.eqProperty<span class="params">(<span class="string">"cat.sex"</span>)</span> )</span>;</span><br><span class="line">session.createCriteria<span class="params">(Cat.class, <span class="string">"cat"</span>)</span></span><br><span class="line">	.add<span class="params">( Property.forName<span class="params">(<span class="string">"weight).gt(avgWeightForSex) )</span><br><span class="line">	.list();</span></span></span></span><br></pre></td></tr></table></figure>
<h2 id="SQL查询">SQL查询</h2><p>SQL查询是通过SQLQuery接口来表示的。Query接口的子接口，可调用Query接口的方法：setFirstResult、setMaxResults、list。</p>
<p>此外还有两个重载的方法。</p>
<ul>
<li>addEntity()：将查询到的记录与特定的实体关联。</li>
<li>addScalar()：将查询到的记录关联成标量值。</li>
</ul>
<p>执行SQL查询的步骤如下：</p>
<ol>
<li>获取Hibernate Session对象 </li>
<li>编写SQL语句</li>
<li>以SQL语句为参数，调用Session的createSQLQuery方法创建查询对象</li>
<li>调用SQLQuery对象的addScalar或addEntity方法将选出的结果与标量值或实体进行关联，分别用于进行标量查询或实体查询。</li>
<li>如果SQL语句包含参数，则调用Query的setxxx方法为参数赋值。</li>
<li>调用Query的list方法返回查询的结果集。</li>
</ol>
<h3 id="标量查询">标量查询</h3><figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">session.createSQLQuery<span class="params">(<span class="string">"select * from student_inf"</span>)</span></span><br><span class="line">    .addScalar<span class="params">(<span class="string">"name"</span>,StandardBasicTypes.STRING)</span></span><br><span class="line">    .list<span class="params">()</span>;</span><br></pre></td></tr></table></figure>
<p>list方法返回数组元素的List，但是像上面程序指定了name列，只会返回单个变量值的List</p>
<p>addScalar的作用</p>
<ul>
<li>指定查询结果包含哪些数据列—没有被addScalar选出的列将不会包含在查询结果中。</li>
<li>指定查询结果中数据列的数据类型。</li>
</ul>
<h3 id="实体查询">实体查询</h3><p>如果查询返回了某个数据表的全部数据列（<strong>记住：是选出全部数据列</strong>），且该数据表有对应的持久化类映射，我们就可把查询结果转换成实体查询。将查询结果转换成实体，可以使用addEntity方法。</p>
<figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">List</span> <span class="built_in">list</span> = session.createSQLQuery(<span class="string">"select enrolment_inf where year=:year"</span>)</span><br><span class="line">        .addEntity(<span class="type">Enrolment</span>.<span class="keyword">class</span>)</span><br><span class="line">        .setInteger(<span class="string">"year"</span>,<span class="number">2005</span>)</span><br><span class="line">        .<span class="built_in">list</span><span class="literal">()</span>;</span><br></pre></td></tr></table></figure>
<p>可以看出原生SQL语句一样支持使用参数。</p>
<p>Hibernate还支持将查询结果转换成多个实体。如果要将查询结果转换成多个实体，则需要指定别名，并调用addEntity(String alias, Class entityClass)方法将不同数据表转换成不同实体。<br>Hibernate还可将查询的结果转换成非持久化实体，只要该JavaBean为这些数据列提供了对应的setter和getter方法。</p>
<figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">List</span> <span class="built_in">list</span> = session.createSQLQuery(<span class="type">SQLQuery</span>).setResultTransformer(<span class="type">Transformers</span>.aliasToBean(<span class="type">StudentCourse</span>.<span class="keyword">class</span>)).<span class="built_in">list</span><span class="literal">()</span>;</span><br></pre></td></tr></table></figure>
<h3 id="处理关联和继承">处理关联和继承</h3><p>将关联实体转换成查询结果的方法是SQLQuery addJoin(String alias, String path)，该方法第一个参数是转换后的实体名，第二个参数是待转换的实体属性。</p>
<figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public <span class="type">void</span> joinQuery()&#123;</span><br><span class="line">    <span class="type">Session</span> session = <span class="type">HibernateUtil</span>.currentSession();</span><br><span class="line">    <span class="type">Transaction</span> tx = session.beginTransaction();</span><br><span class="line">    <span class="type">String</span> sql = <span class="string">"select s.*,e.* from student_inf s,enrolment_inf e where s.student_id=e.student_id"</span>;</span><br><span class="line">    <span class="type">List</span> list = session.createSQLQuery(sql)</span><br><span class="line">                .addEntity(<span class="string">"s"</span>,<span class="type">Student</span>.class)</span><br><span class="line">                .addJoin(<span class="string">"e"</span>,<span class="string">"s.enrolments"</span>)</span><br><span class="line">                .list();</span><br><span class="line">    tx.commit();</span><br><span class="line">    <span class="type">HibernateUtil</span>.closeSession();</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">Iterator</span> <span class="keyword">iterator</span> = list.<span class="keyword">iterator</span>();<span class="keyword">iterator</span>.hasNext();)&#123;</span><br><span class="line">        //每个集合元素都是<span class="type">Person</span>、<span class="type">MyEvent</span>所组成的数组</span><br><span class="line">        <span class="type">Object</span>[] objects = (<span class="type">Object</span>[]) <span class="keyword">iterator</span>.next();</span><br><span class="line">        <span class="type">Student</span> stu = (<span class="type">Student</span>) objects[<span class="number">0</span>];</span><br><span class="line">        <span class="type">Enrolments</span> e = (<span class="type">Enrolments</span>) objects[<span class="number">1</span>];</span><br><span class="line">        <span class="type">System</span>.<span class="keyword">out</span>.println(s.getName()+<span class="string">"\t"</span>+e.getYear());</span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的程序中可以看到的，程序将s.enrolments属性转换成别名为e的实体，也就是说程序执行的结果是Student、Enrolment对象数组的列表。</p>
<h3 id="命名SQL查询">命名SQL查询</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@SqlResultSetMapping</span>(name=<span class="string">"compositekey"</span>,</span><br><span class="line">        entities=<span class="annotation">@EntityResult</span>(entityClass=SpaceShip.class,</span><br><span class="line">            fields = &#123;</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"name"</span>, column = <span class="string">"name"</span>),</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"model"</span>, column = <span class="string">"model"</span>),</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"speed"</span>, column = <span class="string">"speed"</span>),</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"captain.firstname"</span>, column = <span class="string">"firstn"</span>),</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"captain.lastname"</span>, column = <span class="string">"lastn"</span>),</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"dimensions.length"</span>, column = <span class="string">"length"</span>),</span><br><span class="line">                    <span class="annotation">@FieldResult</span>(name=<span class="string">"dimensions.width"</span>, column = <span class="string">"width"</span>)</span><br><span class="line">                    &#125;),</span><br><span class="line">        columns = &#123; <span class="annotation">@ColumnResult</span>(name = <span class="string">"surface"</span>),</span><br><span class="line">                    <span class="annotation">@ColumnResult</span>(name = <span class="string">"volume"</span>) &#125; )</span><br><span class="line"></span><br><span class="line"><span class="annotation">@NamedNativeQuery</span>(name=<span class="string">"compositekey"</span>,</span><br><span class="line">    query=<span class="string">"select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as surface from SpaceShip"</span>, </span><br><span class="line">    resultSetMapping=<span class="string">"compositekey"</span>)</span><br><span class="line">&#125; )</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpaceShip</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String model;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">double</span> speed;</span><br><span class="line">    <span class="keyword">private</span> Captain captain;</span><br><span class="line">    <span class="keyword">private</span> Dimensions dimensions;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Id</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@ManyToOne</span>(fetch= FetchType.LAZY)</span><br><span class="line">    <span class="annotation">@JoinColumns</span>( &#123;</span><br><span class="line">            <span class="annotation">@JoinColumn</span>(name=<span class="string">"fname"</span>, referencedColumnName = <span class="string">"firstname"</span>),</span><br><span class="line">            <span class="annotation">@JoinColumn</span>(name=<span class="string">"lname"</span>, referencedColumnName = <span class="string">"lastname"</span>)</span><br><span class="line">            &#125; )</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Captain <span class="title">getCaptain</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> captain;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCaptain</span><span class="params">(Captain captain)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.captain = captain;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getModel</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> model;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setModel</span><span class="params">(String model)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.model = model;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">getSpeed</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> speed;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setSpeed</span><span class="params">(<span class="keyword">double</span> speed)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.speed = speed;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Dimensions <span class="title">getDimensions</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> dimensions;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setDimensions</span><span class="params">(Dimensions dimensions)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.dimensions = dimensions;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@IdClass</span>(Identity.class)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Captain</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String firstname;</span><br><span class="line">    <span class="keyword">private</span> String lastname;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Id</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getFirstname</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> firstname;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setFirstname</span><span class="params">(String firstname)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.firstname = firstname;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Id</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getLastname</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> lastname;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setLastname</span><span class="params">(String lastname)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.lastname = lastname;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>使用Session的getNamedQuery即可获取指定命名SQL查询。</p>
<figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">session.getNamedQuery(<span class="string">"compositekey"</span>).<span class="built_in">list</span><span class="literal">()</span>;</span><br></pre></td></tr></table></figure>
<h3 id="调用存储过程">调用存储过程</h3><p>Hibernate可以通过命名SQL查询来调用存储过程或函数。对于函数，该函数必须返回一个结果集；对于存储过程，该存储过程的第一个参数必须是传出参数，且数据类型是结果集。</p>
<figure class="highlight oxygene"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">create</span> <span class="function"><span class="keyword">procedure</span> <span class="title">select_all_student</span><span class="params">()</span></span><br><span class="line"><span class="title">select</span> *</span><br><span class="line"><span class="title">from</span> <span class="title">student_inf</span>;</span></span><br></pre></td></tr></table></figure>
<p>如果需要使用该存储过程，可以先将其定义成命名SQL查询，当使用原生SQL来调用存储过程或触发器时，应为<code>&lt;sql-query.../&gt;</code>元素指定<code>callable=&quot;true&quot;</code>。还需要使用<code>&lt;return-property .../&gt;</code>子元素将指定列转换成实体的属性。</p>
<figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;sql-query <span class="property">name</span>=<span class="string">"callProcedure"</span> callable=<span class="string">"true"</span>&gt;</span><br><span class="line">    &lt;<span class="constant">return</span> <span class="type">class</span>=<span class="string">"Student"</span>&gt;</span><br><span class="line">        &lt;<span class="constant">return</span>-<span class="keyword">property</span> <span class="property">name</span>=<span class="string">"studentNumber"</span> column=<span class="string">"student_id"</span>/&gt;</span><br><span class="line">        &lt;<span class="constant">return</span>-<span class="keyword">property</span> <span class="property">name</span>=<span class="string">"name"</span> column=<span class="string">"name"</span>/&gt;</span><br><span class="line">    &lt;/<span class="constant">return</span>&gt;</span><br><span class="line">    &#123;call select_all_student()&#125;</span><br><span class="line">&lt;/sql-query&gt;</span><br></pre></td></tr></table></figure>
<p>调用存储过程</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">private void callProcedure<span class="params">()</span>&#123;</span><br><span class="line">    Session session = HibernateUtil.currentSession<span class="params">()</span>;</span><br><span class="line">    Transaction tx=session.beginTransaction<span class="params">()</span>;</span><br><span class="line">    List list = session.getNamedQuery<span class="params">(<span class="string">"callProcedure"</span>)</span>.list<span class="params">()</span>;</span><br><span class="line">    tx.commit<span class="params">()</span>;</span><br><span class="line">    HibernateUtil.closeSession<span class="params">()</span>;</span><br><span class="line">    <span class="comment">//遍历结果集</span></span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>注意</p>
<ul>
<li>建议采用的调用方式是标准SQL92语法，如<code>{?=call functionName(&lt;parameters&gt;)}</code>或 <code>{callprocedureName(&lt;parameters&gt;)}</code>，不支持原生的调用语法。</li>
<li>因为存储过程本身完成了查询的全部操作。因此，调用存储过程进行的查询无法使用setFirstResult/setMaxResults进行分页。</li>
</ul>
<p>对于Oracle有如下规则:</p>
<ul>
<li>存储过程必须返回一个结果集.它通过返回<code>SYS_REFCURSOR</code>实现(在Oracle9或10),在Oracle里你需要定义一个<code>REF CURSOR</code> 类型</li>
<li>推荐的格式是<code>{ ? = call procName(&lt;parameters&gt;) }</code>或<code>{ ? = call procName }</code>(这更像是Oracle规则而不是Hibernate规则)</li>
</ul>
<p>对于Sybase或者MS SQL server有如下规则:</p>
<ul>
<li>存储过程必须返回一个结果集。.注意这些servers可能返回多个结果集以及更新的数目.Hibernate将取出第一条结果集作为它的返回值， 其他将被丢弃。</li>
<li>如果你能够在存储过程里设定SET NOCOUNT ON，这可能会效率更高，但这不是必需的。</li>
</ul>
<h3 id="定制SQL">定制SQL</h3><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@Table</span>(name=<span class="string">"CHAOS"</span>)</span><br><span class="line"><span class="annotation">@SQLInsert</span>( sql=<span class="string">"INSERT INTO CHAOS(size, name, nickname, id) VALUES(?,upper(?),?,?)"</span>)</span><br><span class="line"><span class="annotation">@SQLUpdate</span>( sql=<span class="string">"UPDATE CHAOS SET size = ?, name = upper(?), nickname = ? WHERE id = ?"</span>)</span><br><span class="line"><span class="annotation">@SQLDelete</span>( sql=<span class="string">"DELETE CHAOS WHERE id = ?"</span>)</span><br><span class="line"><span class="annotation">@SQLDeleteAll</span>( sql=<span class="string">"DELETE CHAOS"</span>)</span><br><span class="line"><span class="annotation">@Loader</span>(namedQuery = <span class="string">"chaos"</span>)</span><br><span class="line"><span class="annotation">@NamedNativeQuery</span>(name=<span class="string">"chaos"</span>, query=<span class="string">"select id, size, name, lower( nickname ) as nickname from CHAOS where id= ?"</span>, resultClass = Chaos.<span class="keyword">class</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Chaos</span> &#123;</span></span><br><span class="line">    <span class="annotation">@Id</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> Long size;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String nickname;</span><br><span class="line">    <span class="comment">//setter and getter</span></span><br><span class="line">    ....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>也可以使用xml配置文件形式</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;class name=<span class="string">"Person"</span>&gt;</span><br><span class="line">    &lt;id name=<span class="string">"id"</span>&gt;</span><br><span class="line">        &lt;generator class=<span class="string">"increment"</span>/&gt;</span><br><span class="line">    &lt;/id&gt;</span><br><span class="line">    &lt;property name=<span class="string">"name"</span> not-null=<span class="string">"true"</span>/&gt;</span><br><span class="line">    &lt;sql-insert&gt;INSERT INTO <span class="keyword">PERSON</span> (NAME, ID) VALUES ( UPPER(?), ? )&lt;/sql-insert&gt;</span><br><span class="line">    &lt;sql-update&gt;UPDATE <span class="keyword">PERSON</span> SET NAME=UPPER(?) WHERE ID=?&lt;/sql-update&gt;</span><br><span class="line">    &lt;sql-delete&gt;DELETE FROM <span class="keyword">PERSON</span> WHERE ID=?&lt;/sql-delete&gt;</span><br><span class="line">&lt;/class&gt;</span><br></pre></td></tr></table></figure>
<p>使用存储过程也是可以的，需要指定<code>callable=&quot;true&quot;</code>，调用存储过程的顺序必须和Hibernate所期待的顺序相同。程序将日志调试级别设为<code>org.hibernate.persister.entity</code>。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">class</span> <span class="attribute">name</span>=<span class="value">"Person"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">id</span> <span class="attribute">name</span>=<span class="value">"id"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">generator</span> <span class="attribute">class</span>=<span class="value">"increment"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"name"</span> <span class="attribute">not-null</span>=<span class="value">"true"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">sql-insert</span> <span class="attribute">callable</span>=<span class="value">"true"</span>&gt;</span>&#123;call createPerson(?,?)&#125;<span class="tag">&lt;/<span class="title">sql-insert</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">sql-update</span> <span class="attribute">callable</span>=<span class="value">"true"</span>&gt;</span>&#123;? = call updatePerson(?)&#125;<span class="tag">&lt;/<span class="title">sql-delete</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">sql-delete</span> <span class="attribute">callable</span>=<span class="value">"true"</span>&gt;</span>&#123;? = call deletePerson(?)&#125;<span class="tag">&lt;/<span class="title">sql-delete</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">class</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h2 id="数据过滤">数据过滤</h2><p>过滤器和定义在类和集合映射文件上的<code>where</code>属性非常相似。它们的区别是过滤器可以带参数，应用程序可以在运行时决定是否启用指定的过滤器，使用怎样的参数值。而映射文见上的<code>where</code>属性将一直生效，且无法动态传入参数。</p>
<p>过滤器的用法很想数据库视图，区别是视图在数据库中已经定义完成，而过滤器则还需在应用程序中确定参数值。</p>
<p>@org.hibernate.annotations.FilterDef 或 @FilterDefs 定义过滤器声明,为同名过滤器所用. 过滤器声明带有一个name()和一个parameters()数组,@ParamDef包含name和type, 你还可以为给定的@filterDef定义一个defaultCondition()参数, 当@Filter中没有任何定义时,可使用该参数定义缺省条件. @FilterDef (s)可以在类或包一级进行定义.</p>
<p>现在我们来定义应用于实体或集合加载时的SQL过滤器子句.我们使用@Filter,并将其置于实体或集合元素上。<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@FilterDef</span>(name=<span class="string">"minLength"</span>, parameters=<span class="variable">@ParamDef</span>( name=<span class="string">"minLength"</span>, type=<span class="string">"integer"</span> ) )</span><br><span class="line"><span class="variable">@Filters</span>( &#123;</span><br><span class="line">    <span class="variable">@Filter</span>(name=<span class="string">"betweenLength"</span>, condition=<span class="string">":minLength &lt;= length and :maxLength &gt;= length"</span>),</span><br><span class="line">    <span class="variable">@Filter</span>(name=<span class="string">"minLength"</span>, condition=<span class="string">":minLength &lt;= length"</span>)</span><br><span class="line">&#125; )</span><br><span class="line">public class Forest &#123; ... &#125;</span><br></pre></td></tr></table></figure></p>
<p>过滤器的目标是实体表，使用@Filter，如果是关联表使用@FilterJoinTable<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@OneToMany</span></span><br><span class="line"><span class="variable">@JoinTable</span></span><br><span class="line"><span class="comment">//filter on the target entity table</span></span><br><span class="line"><span class="variable">@Filter</span>(name=<span class="string">"betweenLength"</span>, condition=<span class="string">":minLength &lt;= length and :maxLength &gt;= length"</span>)</span><br><span class="line"><span class="comment">//filter on the association table</span></span><br><span class="line"><span class="variable">@FilterJoinTable</span>(name=<span class="string">"security"</span>, condition=<span class="string">":userlevel &gt;= requredLevel"</span>)</span><br><span class="line">public Set&lt;Forest&gt; <span class="function">getForests</span>() &#123; ... &#125;</span><br></pre></td></tr></table></figure></p>
<p>默认情况下，Hibernate自动确定@Filter SQL条件中的所有点，这样别名需要被注入，设置@Filter中deduceAliasInjectionPoints为false。然后使用@SqlFragmentAlias注解，在SQL的条件语句中使用{alias}占位符。<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@Entity</span></span><br><span class="line"><span class="variable">@Table</span>(name=<span class="string">"T_TREE"</span>)</span><br><span class="line"><span class="variable">@Filters</span>(&#123;</span><br><span class="line">    <span class="variable">@Filter</span>(name=<span class="string">"isTall"</span>, condition=<span class="string">"&#123;alias&#125;.LENGTH &gt;= 100"</span>, deduceAliasInjectionPoints = false),</span><br><span class="line">    <span class="variable">@Filter</span>(name=<span class="string">"isOak"</span>, condition=<span class="string">"&#123;t&#125;.WOODTYPE like 'oak'"</span>, deduceAliasInjectionPoints = false,</span><br><span class="line">        aliases=&#123;<span class="variable">@SqlFragmentAlias</span>(alias=<span class="string">"t"</span>, table=<span class="string">"T_TREE"</span>)&#125;)</span><br><span class="line">&#125;)</span><br><span class="line">public class Tree &#123; ... &#125;</span><br></pre></td></tr></table></figure></p>
<p>对于xml配置文件方式，系统默认不启用过滤器，必须通过Session的enableFilter(String filterName)才可以启用过滤器，该方法返回一个Filter实例，Filter包含setParameter方法用于为过滤器参数赋值。</p>
<p>通常来说，如果某个筛选条件使用得非常频繁，那么我们可以将该筛选条件设置为过滤器；如果是临时的数据筛选，还是使用常规查询比较好。对于在SQL语句中使用行内表达式、视图的地方，现在可考虑使用过滤器。</p>
<h2 id="事物控制">事物控制</h2><h3 id="事务的概念">事务的概念</h3><p>事务是一步或几步基本操作组成的逻辑执行单元，这些基本操作作为一个整体执行单元，它们要么全部执行，要么全部取消，绝不能仅仅执行部分。一般而言，每次用户请求，对应一个业务逻辑方法，一个业务逻辑方法往往具有逻辑上的原子性，应该使用事务。</p>
<p>事务具备4个特性：原子性（Atomicity）、一致性（Consistency）、隔离性（Isolation）和持续性（Durability）。这四个特性简称ACID性。</p>
<h3 id="Session与事务">Session与事务</h3><p>Hibernate的事务（Transaction对象）通过Session的beginTransaction方法显式打开，Hibernate自身并不提供事务控制行为，底层直接使用JDBC连接、JTA资源或其他资源的事务。</p>
<p>从编程角度来看，Hibernate的事务由Session对象开启；从底层实现来看，Hibernate事务由TransactionFactory的实例来产生。</p>
<p>TransactionFactory是一个事务工厂的接口，有不同实现：CMTTransactionFactory（针对容器管理事务环境的实现类）、JDBCTransactionFactory（针对JDBC局部事务环境的实现类）、JTATransactionFactory（针对JTA全局事务环境的实现类）。</p>
<p>SessionFactory底层封装了TransactionFactory。SessionFactory创建的代价很高，它是线程安全的对象，被设计成可以被所有线程所共享。通常，SessionFactory会在应用启动时创建，一旦创建将不会轻易关闭，只有退出时才关闭。</p>
<p>Session是轻量级的，是线程不安全的。对于单个业务进程、单个的工作单元而言，Session只被使用一次。创建Session时，并不会立即打开与数据库之间的连接，只有需要进行数据库操作时，Session才会获取JDBC连接。因此，打开和关闭Session，并不会对性能造成很大影响。甚至即使无法确定一个请求是否需要数据访问，也可以打开Session对象，因为如果不进行数据库访问，Session不会获取JDBC连接。</p>
<p>数据库事务应该尽可能短，降低数据库锁定造成的资源争用。</p>
<p>Hibernate的所有持久化访问都必须在Session管理下进行，但并不推荐因为一次简单的数据库原子操作，就打开和关闭一次Session，数据库事务也是如此。</p>
<p>Hibernate建议采用每个请求对应一次Session的模式—因此一次请求通常表示需要执行一个完整的业务功能，这个功能由系列的数据库原子操作组成，而且它们应该是一个逻辑上的整体。</p>
<p>对于长事务，Hibernate有如下三种模式：</p>
<ul>
<li>自动版本化 - Hibernate能够自动进行乐观并发控制，如果在用户思考的过程中发生并发修改冲突，Hibernate能够自动检测到。</li>
<li>脱管对象（Detached Objects）- 如果你决定采用前面已经讨论过的 session-per-request模式，所有载入的实例在用户思考的过程中都处于与Session脱离的状态。Hibernate允许你把与Session脱离的对象重新关联到Session上，并且对修改进行持久化，这种模式被称为 session-per-request-with-detached-objects。自动版本化被用来隔离并发修改。</li>
<li>长生命周期的Session （Long Session）- Hibernate 的Session 可以在数据库事务提交之后和底层的JDBC连接断开，当一个新的客户端请求到来的时候，它又重新连接上底层的 JDBC连接。这种模式被称之为session-per-application-transaction，这种情况可 能会造成不必要的Session和JDBC连接的重新关联。自动版本化被用来隔离并发修改。</li>
</ul>
<p>如果程序打开Session很长时间，或载入过多数据，Session占用的内存会一直增长，直到抛出OutOfMemoryException。可以通过clear和evict方法管理Session的缓存。对于大批量的数据处理，推荐使用DML风格 的HQL语句完成。</p>
<p>如果在Session范围之外，访问未初始化的集合或代理（由Hibernate的延迟加载特性所引起），HIbernate将会抛出LazyInitializationException异常。</p>
<p>Hibernate的initialize静态方法可以强制初始化某个集合或代理。只要Session处于open状态，Hibernate.initialize(teacher)将会初始化teacher代理。</p>
<p>两种方法保证Session处于打开状态：</p>
<ul>
<li>在一个Web应用中，可以利用过滤器，在用户请求结束、页面生成结束时关闭Session。也就是保证视图显示层一直打开Session，这就是所谓的Open Session in View模式。当然采用这种模式时必须保证所有异常得到正确处理，在呈现视图界面之前，或在生成视图界面的过程中发生异常时，必须保证可以正确关闭Session，并结束事务。（Spring框架提供的OpenSessionInViewFilter就可以满足这个要求。</li>
<li>使用业务逻辑层负责准备数据，在业务逻辑层返回数据之前，业务逻辑层对每个所需集合调用Hibernate.initialize()方法，或者使用带fetch子句或FetchMode.JOIN的查询，事先取得所有数据，并将这些数据封装成VO（值对象）集合，然后程序可以关闭Session了。业务逻辑层将VO集传入视图层，让视图层只负责简单的显示逻辑。这种模式下，可以让视图层和Hibernate API彻底分离，保证视图层不会出现持久层API。</li>
</ul>
<h3 id="上下文相关的会话">上下文相关的会话</h3><p>从 3.1 开始，SessionFactory.getCurrentSession() 的后台实现是可拔插的。因此，我们引入了新的扩展接口（org.hibernate.context.CurrentSessionContext）和新的配置参数（hibernate.current_session_context_class），以便对什么是当前会话的范围（scope）和上下文（context）的定义进行拔插。</p>
<p>Hibernate 内置了org.hibernate.context.CurrentSessionContext 接口的三种实现：</p>
<ul>
<li>org.hibernate.context.JTASessionContext：当前会话根据 JTA 来跟踪和界定。这和以前的仅支持 JTA 的方法是完全一样的。详情请参阅 Javadoc。</li>
<li>org.hibernate.context.ThreadLocalSessionContext：当前会话通过当前执行的线程来跟踪和界定。详情也请参阅 Javadoc。</li>
<li>org.hibernate.context.ManagedSessionContext：当前会话通过当前执行的线程来跟踪和界定。但是，你需要负责使用这个类的静态方法将 Session 实例绑定、或者取消绑定，它并不会打开（open）、flush 或者关闭（close）任何 Session。</li>
</ul>
<p>对于在容器中使用Hibernate的场景而言，通常会采用第一种方式；对于独立的Hibernate应用而言，通常会采用第二种方式。</p>
<p>在hibernate.cfg.xml文件中增加以下中的一种配置<br><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="keyword">property</span> <span class="property">name</span>=<span class="string">"hibernate.current_session_context_class"</span>&gt;thread&lt;/<span class="keyword">property</span>&gt;</span><br><span class="line">&lt;<span class="keyword">property</span> <span class="property">name</span>=<span class="string">"hibernate.current_session_context_class"</span>&gt;jta&lt;/<span class="keyword">property</span>&gt;</span><br><span class="line">&lt;<span class="keyword">property</span> <span class="property">name</span>=<span class="string">"hibernate.current_session_context_class"</span>&gt;managed&lt;/<span class="keyword">property</span>&gt;</span><br></pre></td></tr></table></figure></p>
<h2 id="二级缓存和查询缓存">二级缓存和查询缓存</h2><p>Hibernate 两个级别的缓存</p>
<ul>
<li>默认总是启用的Session级别的一级缓存</li>
<li>可选的SessionFactory级别的二级缓存</li>
</ul>
<p>其中Session级别的一级缓存不需要开发者关心，默认总是有效的，当应用保存持久化实体、修改持久化实体时，Session并不会立即把这种改变flush到数据库，而是缓存在当前Session的一级缓存中，除非程序显式调用Session的flush方法，或程序关闭Session时才会把这些改变一次性flush到底层数据库。</p>
<p>SessionFactory级别的二级缓存是全局性的，应用的所有Session都共享这个二级缓存。不过此级别的缓存默认是关闭的，必须由程序显式开启。Session优先从二级缓存抓取数据。</p>
<h3 id="开启二级缓存">开启二级缓存</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--开启二级缓存--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.cache.use_second_level_cache"</span>&gt;</span>true<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--设置二级缓存实现类--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.cache.provider_class"</span>&gt;</span>org.hibernate.cache.EhCacheProvider<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>缓存策略提供商（Cache Providers）</p>
<table>
<thead>
<tr>
<th>Cache</th>
<th>Provider class</th>
<th>Type</th>
<th>Cluster Safe</th>
<th>Query Cache Supported</th>
</tr>
</thead>
<tbody>
<tr>
<td>Hashtable</td>
<td>org.hibernate.cache.HashtableCacheProvider</td>
<td>memory</td>
<td></td>
<td>yes</td>
</tr>
<tr>
<td>EHCache</td>
<td>org.hibernate.cache.EhCacheProvider</td>
<td>memory, disk</td>
<td></td>
<td>yes</td>
</tr>
<tr>
<td>OSCache</td>
<td>org.hibernate.cache.OSCacheProvider</td>
<td>memory, disk</td>
<td></td>
<td>yes</td>
</tr>
<tr>
<td>SwarmCache</td>
<td>org.hibernate.cache.SwarmCacheProvider</td>
<td>clustered (ip multicast)</td>
<td>yes (clustered invalidation)</td>
<td></td>
</tr>
<tr>
<td>JBoss Cache    1.x</td>
<td>org.hibernate.cache.TreeCacheProvider</td>
<td>clustered (ip multicast), transactional</td>
<td>yes (replication)</td>
<td>yes (clock sync req.)</td>
</tr>
<tr>
<td>JBoss Cache    2</td>
<td>org.hibernate.cache.jbc.JBossCacheRegionFactory</td>
<td>clustered (ip multicast), transactional</td>
<td>yes (replication)</td>
<td>yes (clock sync req.)</td>
</tr>
</tbody>
</table>
<p>EHCache缓存配置文件ehcache.xml，将其放在类加载路径下稍作修改即可。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="title">ehcache</span>&gt;</span>  </span><br><span class="line">　<span class="tag">&lt;<span class="title">diskStore</span> <span class="attribute">path</span>=<span class="value">"java.io.tmpdir"</span>/&gt;</span>    </span><br><span class="line">    <span class="comment">&lt;!--maxElementsInMemory设置缓存中最多可放多少个对象</span><br><span class="line">    eternal设置缓存是否永久有效</span><br><span class="line">    timeToldleSeconds设置缓存的对象多少秒没有被使用就会清理掉</span><br><span class="line">    timeToLiveSeconds设置缓存的对象在过期之前可以缓存多少秒</span><br><span class="line">    diskPersistent设置缓存是否被持久化到硬盘中，保存路径由diskStore元素指定</span><br><span class="line">    --&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="title">defaultCache</span>  </span><br><span class="line">　　　<span class="attribute">maxElementsInMemory</span>=<span class="value">"10000"</span></span><br><span class="line">　　　<span class="attribute">eternal</span>=<span class="value">"false"</span> </span><br><span class="line">　　　<span class="attribute">overflowToDisk</span>=<span class="value">"true"</span> </span><br><span class="line">　　　<span class="attribute">timeToIdleSeconds</span>=<span class="value">"300"</span></span><br><span class="line">　　　<span class="attribute">timeToLiveSeconds</span>=<span class="value">"180"</span> </span><br><span class="line">　　　<span class="attribute">diskPersistent</span>=<span class="value">"false"</span></span><br><span class="line">　　　<span class="attribute">diskExpiryThreadIntervalSeconds</span>= "<span class="attribute">120</span>"/&gt;</span>    </span><br><span class="line"><span class="tag">&lt;/<span class="title">ehcache</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>@org.hibernate.annotations.Cache定义了缓存策略及给定的二级缓存的范围. 此注解适用于根实体(非子实体),还有集合.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Entity</span></span><br><span class="line"><span class="annotation">@Cache</span>(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Forest</span> </span>&#123; ... &#125;</span><br><span class="line">    <span class="annotation">@OneToMany</span>(cascade=CascadeType.ALL, fetch=FetchType.EAGER)</span><br><span class="line">    <span class="annotation">@JoinColumn</span>(name=<span class="string">"CUST_ID"</span>)</span><br><span class="line">    <span class="annotation">@Cache</span>(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> SortedSet&lt;Ticket&gt; <span class="title">getTickets</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> tickets;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">@Cache<span class="params">(</span><br><span class="line">    CacheConcurrencyStrategy usage<span class="params">()</span>;                 <span class="params">(<span class="number">1</span>)</span></span><br><span class="line">    String region<span class="params">()</span> default <span class="string">""</span>;                       <span class="params">(<span class="number">2</span>)</span></span><br><span class="line">    String include<span class="params">()</span> default <span class="string">"all"</span>;                   <span class="params">(<span class="number">3</span>)</span></span><br><span class="line">)</span></span><br></pre></td></tr></table></figure>
<p>(1)    usage: 给定缓存的并发策略(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)<br>(2)    region (可选的)：缓存范围(默认为类的全限定类名或是集合的全限定角色名)<br>(3)    include (可选的)：值为all时包括了所有的属性(proterty), 为non-lazy时仅含非延迟属性(默认值为all)</p>
<ul>
<li>只读策略缓存（Strategy: read only）<br>  如果你的应用程序只需读取一个持久化类的实例，而无需对其修改， 那么就可以对其进行只读 缓存。这是最简单，也是实用性最好的方法。甚至在集群中，它也能完美地运作。</li>
<li>读/写策略（Strategy: read/write）<br>  如果应用程序需要更新数据，那么使用读/写缓存 比较合适。 如果应用程序要求“序列化事务”的隔离级别（serializable transaction isolation level），那么就决不能使用这种缓存策略。 如果在JTA环境中使用缓存，你必须指定hibernate.transaction.manager_lookup_class属性的值， 通过它，Hibernate才能知道该应用程序中JTA的TransactionManager的具体策略。    在其它环境中，你必须保证在Session.close()、或Session.disconnect()调用前， 整个事务已经结束。 如果你想在集群环境中使用此策略，你必须保证底层的缓存实现支持锁定(locking)。Hibernate内置的缓存策略并不支持锁定功能。</li>
<li>非严格读/写策略（Strategy: nonstrict read/write）<br>  如果应用程序只偶尔需要更新数据（也就是说，两个事务同时更新同一记录的情况很不常见），也不需要十分严格的事务隔离， 那么比较适合使用非严格读/写缓存策略。如果在JTA环境中使用该策略， 你必须为其指定hibernate.transaction.manager_lookup_class属性的值， 在其它环境中，你必须保证在Session.close()、或Session.disconnect()调用前， 整个事务已经结束。</li>
<li>事务策略（transactional）<br>  Hibernate的事务缓存策略提供了全事务的缓存支持， 例如对JBoss TreeCache的支持。这样的缓存只能用于JTA环境中，你必须指定 为其hibernate.transaction.manager_lookup_class属性。</li>
</ul>
<h3 id="管理缓存和统计缓存">管理缓存和统计缓存</h3><p>无论何时，当你给save()、update()或 saveOrUpdate()方法传递一个对象时，或使用load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。</p>
<p>当随后flush()方法被调用时，对象的状态会和数据库取得同步。 如果你不希望此同步操作发生，或者你正处理大量对象、需要对有效管理内存时，你可以调用evict() 方法，从一级缓存中去掉这些对象及其集合。</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">News</span> <span class="keyword">news</span> = (<span class="keyword">News</span>) newsList.<span class="literal">get</span>(0);</span><br><span class="line">sess.evict(<span class="keyword">news</span>);</span><br></pre></td></tr></table></figure>
<p>Session还提供了一个contains()方法，用来判断某个实例是否处于当前session的缓存中。</p>
<p>如若要把所有的对象从session缓存中彻底清除，则需要调用Session.clear()。</p>
<p>对于二级缓存来说，在SessionFactory中定义了许多方法， 清除缓存中实例、整个类、集合实例或者整个集合。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sessionFactory.evict<span class="params">(Cat.class, catId)</span>; <span class="comment">//evict a particular Cat</span></span><br><span class="line">sessionFactory.evict<span class="params">(Cat.class)</span>;  <span class="comment">//evict all Cats</span></span><br><span class="line">sessionFactory.evictCollection<span class="params">(<span class="string">"Cat.kittens"</span>, catId)</span>; <span class="comment">//evict a particular collection of kittens</span></span><br><span class="line">sessionFactory.evictCollection<span class="params">(<span class="string">"Cat.kittens"</span>)</span>; <span class="comment">//evict all kitten collections</span></span><br></pre></td></tr></table></figure>
<p>如若需要查看二级缓存或查询缓存区域的内容，你可以使用统计（Statistics） API。</p>
<p>此时，你必须手工打开统计选项。可选的，你可以让Hibernate更人工可读的方式维护缓存内容。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 开启二级缓存的统计功能 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.generate_statistics"</span>&gt;</span>true<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 设置使用结构化方式来维护缓存项 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.cache.use_structured_entries"</span>&gt;</span>true<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Map cacheEntries = sessionFactory.getStatistics<span class="params">()</span></span><br><span class="line">        .getSecondLevelCacheStatistics<span class="params">(regionName)</span></span><br><span class="line">        .getEntries<span class="params">()</span>;</span><br></pre></td></tr></table></figure>
<h3 id="使用查询缓存">使用查询缓存</h3><p>大部分情况下查询缓存并不能提供应用性能，甚至反而会降低应用性能，因此实际项目中慎重使用查询缓存。</p>
<p>首先在配置文件中增加如下配置<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 启用查询缓存 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">property</span> <span class="attribute">name</span>=<span class="value">"hibernate.cache.use_query_cache"</span>&gt;</span>true<span class="tag">&lt;/<span class="title">property</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>此外还需要调用Query对象的setCacheable(true)才会对查询结果进行缓存。</p>
<h2 id="事件机制">事件机制</h2><p>Hibernate的事件框架由两个部分组成</p>
<ul>
<li>拦截器机制：对于特定动作拦截，回调应用中的特定动作。</li>
<li>事件系统：重写Hibernate的事件监听器。</li>
</ul>
<h3 id="拦截器">拦截器</h3><p>Interceptor接口提供了从会话(session)回调(callback)应用程序(application)的机制，这种回调机制可以允许应用程序在持久化对象被保存、更新、删除或是加载之前，检查并（或）修改其属性。一个可能的用途，就是用来跟踪审核(auditing)信息。</p>
<ul>
<li><p>创建会话(session)的时候可以指定拦截器。</p>
  <figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Session</span> session = sf.openSession( <span class="keyword">new</span> <span class="type">MyInterceptor</span><span class="literal">()</span> );</span><br></pre></td></tr></table></figure>
</li>
<li><p>也可以使用Configuration来设置一个全局范围的拦截器。</p>
  <figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="type">Configuration</span><span class="literal">()</span>.setInterceptor( <span class="keyword">new</span> <span class="type">MyInterceptor</span><span class="literal">()</span> );</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="事件系统">事件系统</h3><p>基本上，Session接口的每个方法都有相对应的事件。比如 LoadEvent，FlushEvent，等等（查阅XML配置文件 的DTD，以及org.hibernate.event包来获得所有已定义的事件的列表）。当某个方法被调用时，Hibernate Session会生成一个相对应的事件并激活所有配置好的事件监听器。系统预设的监听器实现的处理过程就是被监听的方法要做的（被监听的方法所做的其实仅仅是激活监听器，“实际”的工作是由监听器完成的）。不过，你可以自由地选择实现一个自己定制的监听器（比如，实现并注册用来处理处理LoadEvent的LoadEventListener接口），来负责处理所有的调用Session的load()方法的请求。</p>
<p>监听器应该被看作是单例(singleton)对象，也就是说，所有同类型的事件的处理共享同一个监听器实例，因此监听器不应该保存任何状态（也就是不应该使用成员变量）。</p>
<p>用户定制的监听器应该实现与所要处理的事件相对应的接口，或者从一个合适的基类继承（甚至是从Hibernate自带的默认事件监听器类继承，为了方便你这样做，这些类都被声明成non-final的了）。用户定制的监听器可以通过编程使用Configuration对象来注册，也可以在Hibernate的XML格式的配置文件中进行声明（不支持在Properties格式的配置文件声明监听器）。下面是一个用户定制的加载事件(load event)的监听器：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">MyLoadListener</span> <span class="keyword"><span class="keyword">extends</span></span> <span class="title">DefaultLoadEventListener</span> &#123;</span></span><br><span class="line">    <span class="comment">// this is the single method defined by the LoadEventListener interface</span></span><br><span class="line">    public <span class="type">Object</span> onLoad(<span class="type">LoadEvent</span> event, <span class="type">LoadEventListener</span>.<span class="type">LoadType</span> loadType)</span><br><span class="line">            <span class="keyword">throws</span> <span class="type">HibernateException</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> ( !<span class="type">MySecurity</span>.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="type">MySecurityException</span>(<span class="string">"Unauthorized access"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.onLoad(event, loadType);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>你还需要修改一处配置，来告诉Hibernate以使用选定的监听器来替代默认的监听器。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">hibernate-configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">session-factory</span>&gt;</span></span><br><span class="line">        ...</span><br><span class="line">        <span class="tag">&lt;<span class="title">listener</span> <span class="attribute">type</span>=<span class="value">"load"</span> <span class="attribute">class</span>=<span class="value">"MyLoadListener"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">session-factory</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">hibernate-configuration</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>一个事件配置多个监听器<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="keyword">event</span> type=<span class="string">"load"</span>&gt;</span><br><span class="line">    &lt;listener <span class="keyword">class</span>=<span class="string">"listener.MyLoadListener"</span> /&gt;</span><br><span class="line">    &lt;listener <span class="keyword">class</span>=<span class="string">"listener.DefaultLoadEventListener"</span> /&gt;</span><br><span class="line">&lt;/<span class="keyword">event</span>&gt;</span><br></pre></td></tr></table></figure></p>
<p>看看用另一种方式，通过编程的方式来注册它。</p>
<figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Configuration</span> cfg = <span class="keyword">new</span> <span class="type">Configuration</span><span class="literal">()</span>;</span><br><span class="line">cfg.getSessionEventListenerConfig<span class="literal">()</span>.setLoadEventListener( <span class="keyword">new</span> <span class="type">MyLoadListener</span><span class="literal">()</span> );</span><br></pre></td></tr></table></figure>
<p>或<br><figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">Configuration</span> cfg = <span class="keyword">new</span> <span class="keyword">Configuration</span>();</span><br><span class="line">cfg.setListener(<span class="string">"load"</span>, <span class="string">"listener.MyLoadListener"</span>);</span><br></pre></td></tr></table></figure></p>
<p>注册多个事件<br><figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">LoadEventListener</span><span class="literal">[]</span> stack = &#123; <span class="keyword">new</span> <span class="type">MyLoadListener</span><span class="literal">()</span>, <span class="keyword">new</span> <span class="type">DefaultLoadEventListener</span><span class="literal">()</span>&#125;;</span><br><span class="line">cfg.getEventListeners<span class="literal">()</span>.setLoadEventListeners(stack);</span><br></pre></td></tr></table></figure></p>
<p>通过在XML配置文件声明而注册的监听器不能共享实例。如果在多个<listener>节点中使用了相同的类的名字，则每一个引用都将会产生一个独立的实例。如果你需要在多个监听器类型之间共享监听器的实例，则你必须使用编程的方式来进行注册。</listener></p>
<p>为什么我们实现了特定监听器的接口，在注册的时候还要明确指出我们要注册哪个事件的监听器呢？ 这是因为一个类可能实现多个监听器的接口。在注册的时候明确指定要监听的事件，可以让启用或者禁用对某个事件的监听的配置工作简单些。</p>
<p>参考：</p>
<p><a href="http://xiaogui9317170.iteye.com/blog/283526" target="_blank" rel="external">基于按annotation的hibernate主键生成策略</a><br><a href="https://docs.jboss.org/hibernate/annotations/3.4/reference/zh_cn/html_single/" target="_blank" rel="external">Hibernate Annotations</a><br><a href="http://www.cnblogs.com/luxh/archive/2012/06/01/2531428.html" target="_blank" rel="external">JPA的查询语言—JPQL的命名查询@NamedQuery</a></p>

      
    </div>
    <footer class="article-footer">
	  
	  <!-- 百度分享 Start -->
	  <div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more"></a><a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a><a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a><a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a><a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网"></a><a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a></div>
	  <!-- 百度分享 End -->
	  
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Hibernate/">Hibernate</a></li></ul>

	  
<span>
Updated:<time datetime="2015-03-13T02:19:24.000Z" itemprop="dateModified">2015-03-13</time>
</span>


    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2015/03/06/spring-note-2/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          Spring笔记二
        
      </div>
    </a>
  
  
    <a href="/2015/02/07/thinking-in-java-note-9/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">Java编程思想笔记九</div>
    </a>
  
</nav>

  
</article>



<!-- 多说评论框 start -->

<section id="comments">
  <div class="ds-thread"  data-thread-key="/2015/03/05/hibernate-note/" data-title="Hibernate笔记" data-url="http://howiefh.github.io/2015/03/05/hibernate-note/" id="ds_thread">
    <noscript>Please enable JavaScript to view the <a href="//duoshuo.com/?ref_noscript">comments powered by duoshuo.</a></noscript>
  </div>
</section>

<!-- 多说评论框 end -->
</section>
        
          
  <div id="toc" class="toc-aside">
  <h2 class="toc-title">Contents</h2>
    
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#对象/关系数据库映射(ORM)"><span class="toc-number">1.</span> <span class="toc-text">对象/关系数据库映射(ORM)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#ORM基本映射方式"><span class="toc-number">1.1.</span> <span class="toc-text">ORM基本映射方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#流行的ORM框架"><span class="toc-number">1.2.</span> <span class="toc-text">流行的ORM框架</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Hibernate入门"><span class="toc-number">2.</span> <span class="toc-text">Hibernate入门</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate下载和安装"><span class="toc-number">2.1.</span> <span class="toc-text">Hibernate下载和安装</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate的数据库操作"><span class="toc-number">2.2.</span> <span class="toc-text">Hibernate的数据库操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#在Eclipse中使用Hibernate"><span class="toc-number">2.3.</span> <span class="toc-text">在Eclipse中使用Hibernate</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Hibernate体系结构"><span class="toc-number">3.</span> <span class="toc-text">Hibernate体系结构</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#深入Hibernate的配置文件"><span class="toc-number">4.</span> <span class="toc-text">深入Hibernate的配置文件</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#JDBC连接属性"><span class="toc-number">4.1.</span> <span class="toc-text">JDBC连接属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数据库方言"><span class="toc-number">4.2.</span> <span class="toc-text">数据库方言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JNDI数据源的连接属性"><span class="toc-number">4.3.</span> <span class="toc-text">JNDI数据源的连接属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate事务属性"><span class="toc-number">4.4.</span> <span class="toc-text">Hibernate事务属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#二级缓存相关属性"><span class="toc-number">4.5.</span> <span class="toc-text">二级缓存相关属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#外连接抓取属性"><span class="toc-number">4.6.</span> <span class="toc-text">外连接抓取属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#其他常用的配置属性"><span class="toc-number">4.7.</span> <span class="toc-text">其他常用的配置属性</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#深入理解持久化对象"><span class="toc-number">5.</span> <span class="toc-text">深入理解持久化对象</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#持久化类的要求"><span class="toc-number">5.1.</span> <span class="toc-text">持久化类的要求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#持久化对象的状态"><span class="toc-number">5.2.</span> <span class="toc-text">持久化对象的状态</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#改变持久化对象状态的方法"><span class="toc-number">5.3.</span> <span class="toc-text">改变持久化对象状态的方法</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#映射"><span class="toc-number">6.</span> <span class="toc-text">映射</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#映射实体"><span class="toc-number">6.1.</span> <span class="toc-text">映射实体</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#映射属性"><span class="toc-number">6.2.</span> <span class="toc-text">映射属性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#非主属性"><span class="toc-number">6.2.1.</span> <span class="toc-text">非主属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#主属性"><span class="toc-number">6.2.2.</span> <span class="toc-text">主属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#乐观锁和不用持久化"><span class="toc-number">6.2.3.</span> <span class="toc-text">乐观锁和不用持久化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#复合属性—组件映射"><span class="toc-number">6.2.4.</span> <span class="toc-text">复合属性—组件映射</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#复合属性—复合主键"><span class="toc-number">6.2.5.</span> <span class="toc-text">复合属性—复合主键</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#集合映射"><span class="toc-number">6.3.</span> <span class="toc-text">集合映射</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#映射继承关系"><span class="toc-number">6.4.</span> <span class="toc-text">映射继承关系</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#每个类一张表"><span class="toc-number">6.4.1.</span> <span class="toc-text">每个类一张表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#每个类层次结构一张表"><span class="toc-number">6.4.2.</span> <span class="toc-text">每个类层次结构一张表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#连接的子类"><span class="toc-number">6.4.3.</span> <span class="toc-text">连接的子类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#从父类继承的属性"><span class="toc-number">6.4.4.</span> <span class="toc-text">从父类继承的属性</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#关联关系映射"><span class="toc-number">6.5.</span> <span class="toc-text">关联关系映射</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—简介"><span class="toc-number">6.5.1.</span> <span class="toc-text">关联关系映射—简介</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—数据库降级使用"><span class="toc-number">6.5.2.</span> <span class="toc-text">关联关系映射—数据库降级使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:1—共享主键"><span class="toc-number">6.5.3.</span> <span class="toc-text">关联关系映射—1:1—共享主键</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:M—外键"><span class="toc-number">6.5.4.</span> <span class="toc-text">关联关系映射—1:M—外键</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—M:N—联接表"><span class="toc-number">6.5.5.</span> <span class="toc-text">关联关系映射—M:N—联接表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:M—联接表"><span class="toc-number">6.5.6.</span> <span class="toc-text">关联关系映射—1:M—联接表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#关联关系映射—1:1—联接表"><span class="toc-number">6.5.7.</span> <span class="toc-text">关联关系映射—1:1—联接表</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#二级缓存"><span class="toc-number">6.6.</span> <span class="toc-text">二级缓存</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#批量处理"><span class="toc-number">7.</span> <span class="toc-text">批量处理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#使用HQL查询"><span class="toc-number">8.</span> <span class="toc-text">使用HQL查询</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#from子句"><span class="toc-number">8.1.</span> <span class="toc-text">from子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#关联和连接"><span class="toc-number">8.2.</span> <span class="toc-text">关联和连接</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#select子句"><span class="toc-number">8.3.</span> <span class="toc-text">select子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HQL查询的聚集函数"><span class="toc-number">8.4.</span> <span class="toc-text">HQL查询的聚集函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#多态查询"><span class="toc-number">8.5.</span> <span class="toc-text">多态查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HQL查询的where子句"><span class="toc-number">8.6.</span> <span class="toc-text">HQL查询的where子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#表达式"><span class="toc-number">8.7.</span> <span class="toc-text">表达式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#order_by子句"><span class="toc-number">8.8.</span> <span class="toc-text">order by子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#group_by子句"><span class="toc-number">8.9.</span> <span class="toc-text">group by子句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#子查询"><span class="toc-number">8.10.</span> <span class="toc-text">子查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#命名查询"><span class="toc-number">8.11.</span> <span class="toc-text">命名查询</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#条件查询"><span class="toc-number">9.</span> <span class="toc-text">条件查询</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#关联和动态关联"><span class="toc-number">9.1.</span> <span class="toc-text">关联和动态关联</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#投影(Projections)、聚合（aggregation）和分组（grouping）"><span class="toc-number">9.2.</span> <span class="toc-text">投影(Projections)、聚合（aggregation）和分组（grouping）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#离线(detached)查询和子查询"><span class="toc-number">9.3.</span> <span class="toc-text">离线(detached)查询和子查询</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SQL查询"><span class="toc-number">10.</span> <span class="toc-text">SQL查询</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#标量查询"><span class="toc-number">10.1.</span> <span class="toc-text">标量查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#实体查询"><span class="toc-number">10.2.</span> <span class="toc-text">实体查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#处理关联和继承"><span class="toc-number">10.3.</span> <span class="toc-text">处理关联和继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#命名SQL查询"><span class="toc-number">10.4.</span> <span class="toc-text">命名SQL查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#调用存储过程"><span class="toc-number">10.5.</span> <span class="toc-text">调用存储过程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#定制SQL"><span class="toc-number">10.6.</span> <span class="toc-text">定制SQL</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#数据过滤"><span class="toc-number">11.</span> <span class="toc-text">数据过滤</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#事物控制"><span class="toc-number">12.</span> <span class="toc-text">事物控制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#事务的概念"><span class="toc-number">12.1.</span> <span class="toc-text">事务的概念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Session与事务"><span class="toc-number">12.2.</span> <span class="toc-text">Session与事务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#上下文相关的会话"><span class="toc-number">12.3.</span> <span class="toc-text">上下文相关的会话</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二级缓存和查询缓存"><span class="toc-number">13.</span> <span class="toc-text">二级缓存和查询缓存</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#开启二级缓存"><span class="toc-number">13.1.</span> <span class="toc-text">开启二级缓存</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#管理缓存和统计缓存"><span class="toc-number">13.2.</span> <span class="toc-text">管理缓存和统计缓存</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用查询缓存"><span class="toc-number">13.3.</span> <span class="toc-text">使用查询缓存</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#事件机制"><span class="toc-number">14.</span> <span class="toc-text">事件机制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#拦截器"><span class="toc-number">14.1.</span> <span class="toc-text">拦截器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#事件系统"><span class="toc-number">14.2.</span> <span class="toc-text">事件系统</span></a></li></ol></li></ol>
    
  </div>

<aside id="sidebar">

  
    
<div class="widget-wrap">
  <h3 class="widget-title">ABOUT ME</h3>
  <ul class="widget about-me">
    
    <li><img class="author" title="About me" src="http://fh-1.qiniudn.com/okal-eltocat.jpg" /></li>
    
    
    <li>Hi,I'm FengHao.</li>
    
    <li>I'll share something interesting and my learning experience with you at this blog.</li>
    
    <li>前博客:<a href="http://hi.baidu.com/idea_star" target="_BLANK">百度空间</a></li>
    
  </ul>
</div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android/">Android</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/C/">C</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Database/">Database</a><span class="category-list-count">13</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/Database/MongoDB/">MongoDB</a><span class="category-list-count">10</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Database/MySQL/">MySQL</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Eclipse/">Eclipse</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/FTP/">FTP</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Hexo/">Hexo</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/">Java</a><span class="category-list-count">20</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/Java/FreeMarker/">FreeMarker</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/Shiro/">Shiro</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/">JavaEE</a><span class="category-list-count">4</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/Hibernate/">Hibernate</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/JSP/">JSP</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/Spring/">Spring</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/">JavaScript</a><span class="category-list-count">5</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/jQuery/">jQuery</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/PHP/">PHP</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Suse/">Suse</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Ubuntu/">Ubuntu</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vim/">Vim</a><span class="category-list-count">8</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/编程/">编程</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/软件/">软件</a><span class="category-list-count">1</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/Android/" style="font-size: 14.75px; color: #65bfa7">Android</a> <a href="/tags/C/" style="font-size: 13.88px; color: #71c1c2">C</a> <a href="/tags/CAS/" style="font-size: 13px; color: #7dc3de">CAS</a> <a href="/tags/Chrome/" style="font-size: 13px; color: #7dc3de">Chrome</a> <a href="/tags/Clean-Code/" style="font-size: 13.88px; color: #71c1c2">Clean Code</a> <a href="/tags/Database/" style="font-size: 13px; color: #7dc3de">Database</a> <a href="/tags/Eclipse/" style="font-size: 13px; color: #7dc3de">Eclipse</a> <a href="/tags/FTP/" style="font-size: 13.88px; color: #71c1c2">FTP</a> <a href="/tags/FreeMarker/" style="font-size: 14.75px; color: #65bfa7">FreeMarker</a> <a href="/tags/Gcc/" style="font-size: 13px; color: #7dc3de">Gcc</a> <a href="/tags/Git/" style="font-size: 14.75px; color: #65bfa7">Git</a> <a href="/tags/Github-Pages/" style="font-size: 13px; color: #7dc3de">Github Pages</a> <a href="/tags/Hexo/" style="font-size: 14.75px; color: #65bfa7">Hexo</a> <a href="/tags/Hibernate/" style="font-size: 13px; color: #7dc3de">Hibernate</a> <a href="/tags/JSP/" style="font-size: 13px; color: #7dc3de">JSP</a> <a href="/tags/JVM/" style="font-size: 14.75px; color: #65bfa7">JVM</a> <a href="/tags/Java/" style="font-size: 14.75px; color: #65bfa7">Java</a> <a href="/tags/JavaMail/" style="font-size: 13px; color: #7dc3de">JavaMail</a> <a href="/tags/JavaScript/" style="font-size: 16.5px; color: #4dbc6f">JavaScript</a> <a href="/tags/Linux/" style="font-size: 13.88px; color: #71c1c2">Linux</a> <a href="/tags/Log/" style="font-size: 13px; color: #7dc3de">Log</a> <a href="/tags/Markdown/" style="font-size: 13.88px; color: #71c1c2">Markdown</a> <a href="/tags/MongoDB/" style="font-size: 20px; color: #1db400">MongoDB</a> <a href="/tags/MySQL/" style="font-size: 13.88px; color: #71c1c2">MySQL</a> <a href="/tags/PHP/" style="font-size: 16.5px; color: #4dbc6f">PHP</a> <a href="/tags/Rhythmbox/" style="font-size: 13px; color: #7dc3de">Rhythmbox</a> <a href="/tags/SSO/" style="font-size: 13px; color: #7dc3de">SSO</a> <a href="/tags/Servlet/" style="font-size: 13px; color: #7dc3de">Servlet</a> <a href="/tags/Shiro/" style="font-size: 13.88px; color: #71c1c2">Shiro</a> <a href="/tags/Spring/" style="font-size: 13.88px; color: #71c1c2">Spring</a> <a href="/tags/Suse/" style="font-size: 13px; color: #7dc3de">Suse</a> <a href="/tags/Thinking-in-Java/" style="font-size: 19.13px; color: #29b61c">Thinking in Java</a> <a href="/tags/Ubuntu/" style="font-size: 17.38px; color: #41ba53">Ubuntu</a> <a href="/tags/Vim/" style="font-size: 18.25px; color: #35b838">Vim</a> <a href="/tags/VirtualBox/" style="font-size: 13px; color: #7dc3de">VirtualBox</a> <a href="/tags/Vsftpd/" style="font-size: 13px; color: #7dc3de">Vsftpd</a> <a href="/tags/jQuery/" style="font-size: 13px; color: #7dc3de">jQuery</a> <a href="/tags/pam-mysql/" style="font-size: 13px; color: #7dc3de">pam_mysql</a> <a href="/tags/小米/" style="font-size: 13px; color: #7dc3de">小米</a> <a href="/tags/软件/" style="font-size: 15.63px; color: #59bd8b">软件</a>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/09/">September 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/08/">August 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/07/">July 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/05/">May 2015</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/04/">April 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/03/">March 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/02/">February 2015</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/12/">December 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/11/">November 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/10/">October 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/09/">September 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/08/">August 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/07/">July 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/06/">June 2014</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/05/">May 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/04/">April 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/03/">March 2014</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">11</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/01/">January 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/12/">December 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/11/">November 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/08/">August 2013</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/07/">July 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/05/">May 2013</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/04/">April 2013</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/03/">March 2012</a><span class="archive-list-count">1</span></li></ul>
    </div>
  </div>


  
    <div class="widget-wrap">
  <h3 class="widget-title">Calendar</h3>
  <div class="widget">
    <div id="g-calendar" class="g-calendar">
        <span class="g-calendar-prev"></span>
		 
        <span class="g-calendar-back"></span>
        <span class="g-calendar-now"></span>
		 
        <span class="g-calendar-next"></span>
        <div class="g-calendar-hd"></div>
        <div class="g-calendar-tit"></div>
        <div class="g-calendar-bd"></div>
    </div>
  </div>
</div>
<script type="text/javascript">
function LGY_calendar(wrapId, options){
    this.oWrap = this.getId(wrapId);
    this.oHead = this.getByClassName('g-calendar-hd',this.oWrap)[0];
    this.oBody = this.getByClassName('g-calendar-bd',this.oWrap)[0];
    this.oTit = this.getByClassName('g-calendar-tit',this.oWrap)[0];
    this.oPrev = this.getByClassName('g-calendar-prev',this.oWrap)[0];
    this.oNext = this.getByClassName('g-calendar-next',this.oWrap)[0];
    this.oNow = this.getByClassName('g-calendar-now',this.oWrap)[0];
    this.oBack = this.getByClassName('g-calendar-back',this.oWrap)[0];
    this.init();
}
LGY_calendar.prototype = {
    ///////////获取ID元素
    getId:function(id){
        return document.getElementById(id);
    },
    ////////获取css类名元素
    getByClassName:function(className,parent){
        var elem = [],
            node = parent != undefined&&parent.nodeType==1?parent.getElementsByTagName('*'):document.getElementsByTagName('*'),
            p = new RegExp("(^|\\s)"+className+"(\\s|$)");
        for(var n=0,i=node.length;n<i;n++){
            if(p.test(node[n].className)){
                elem.push(node[n]);
            }
        }
        return elem;
    },
    //填充日历
    fillDate:function(year,month){
        //本月份第一天是星期几-为显示上个月的天数做铺垫
        var first_day = new Date(year,month,1).getDay(),
        //如果刚好是星期天，则空出一行（显示上个月的天数）
            first_day = first_day == 0?first_day=7:first_day;
        //本月份最后一天是几号
        var final_date = new Date(year,month+1,0).getDate(),
        //上个月的最后一天是几号
            last_date = new Date(year,month,0).getDate(),
        //剩余的格子数--即排在末尾的格子数
            surplus = 42 - first_day - final_date;
        //设置年的链接
        var yearHead = "<a href='/" + "archives/" + year + "/'>" + year + " "+ "</a>"; 
        //设置年的链接
        var monthHead = "";
        var month1 = month + 1;
        if (month1 < 10) {
            monthHead = "<a href='/" + "archives/" + year + "/" + "0" + month1 + "/'>" + " " + month1 + " " + "</a>";
        } else {
            monthHead = "<a href='/" + "archives/" + year + "/" + month1 + "/'>" + " " + month1 + " " + "</a>";
        }
        //设置表头的日历
        this.oHead.innerHTML = yearHead+'年'+monthHead+'月';
        //填充日历执行
        var html = '';
        //上个月的显示天数
        for(var i=0;i<first_day;i++){
            html+='<span class="g-calendar-grey">'+(last_date-(first_day-1)+i)+'</span>';
        }
        //本月的显示天数
        var postdate = new Date("Thu Mar 05 2015 22:49:08 GMT+0800"); 
        if (true && postdate.getFullYear() == year && postdate.getMonth() == month) { 
            html += '<span>1</span><span>2</span><span>3</span><span>4</span><span><a href="/2015/03/05/hibernate-note/" title="Hibernate笔记">5</a></span><span><a href="/2015/03/06/spring-note-2/" title="当天有2篇博客,第一篇:Spring笔记二">6</a></span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span><span><a href="/2015/03/13/jsp-servlet-note/" title="JSP/Servlet及相关技术笔记">13</a></span><span>14</span><span>15</span><span>16</span><span>17</span><span>18</span><span>19</span><span>20</span><span>21</span><span>22</span><span>23</span><span>24</span><span>25</span><span>26</span><span>27</span><span>28</span>';
        } else {
            for(var j=0;j<final_date;j++){        
                html+='<span id="d'+(j+1)+'">'+(j+1)+'</span>';
            }
        }
        //下个月的显示天数
        for(var k=0;k<surplus;k++){
            html+='<span class="g-calendar-grey">'+(k+1)+'</span>';
        }
        //fill
        this.oBody.innerHTML = html;
        // 当前状态
        if(year==this.c_year&&this.c_month==month){
            this.oBody.getElementsByTagName('span')[first_day+this.date-1].className='g-calendar-on';
        }

        // 对所有文章遍历,然后将有文章的日期加上链接,如果文章太多的话,生成页面会很大,去掉了
        
    },
    // next切换
    next:function(){
        var _that = this;
        this.oNext.onclick = function(){
            _that.month++;
            if(_that.month>11){
                _that.month = 0;
                _that.year++;
            }
            // 填充日历
            _that.fillDate(_that.year,_that.month);
        };
    },
    // back 切换
    back:function(){
        var _that = this;
        if(this.oBack != undefined) {
            this.oBack.onclick = function(){
                var postdate = new Date("Thu Mar 05 2015 22:49:08 GMT+0800"); 
                _that.year = postdate.getFullYear();
                _that.month = postdate.getMonth();
                // 填充日历
                _that.fillDate(_that.year,_that.month);
            };
        }
    },
    // now切换
    now:function(){
        var _that = this;
        if(this.oNow != undefined ) {
            this.oNow.onclick = function(){
                var nowDate = new Date(); 
                _that.year = nowDate.getFullYear();
                _that.month = nowDate.getMonth();
                // 填充日历
                _that.fillDate(_that.year,_that.month);
            };
        }
    },
    // prev切换
    prev:function(){
        var _that = this;
        this.oPrev.onclick = function(){
            _that.month--;
            if(_that.month<0){
                _that.month = 11;
                _that.year--;
            }
            // 填充日历
            _that.fillDate(_that.year,_that.month);
        };
    },
    init:function(){
        this.oTit.innerHTML = '<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>';
        // 获取今天的日历时间
        var now = new Date();
        this.c_year = this.year = now.getFullYear();
        this.c_month = this.month = now.getMonth();
        this.date = now.getDate();
        // 初始化--填充日历
        this.fillDate(this.year,this.month);
        //next切换
        this.next();
        //prev切换
        this.prev();
        //back 切换
        this.back();
        //now 切换
        this.now();
    }
}
new LGY_calendar('g-calendar');
</script>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2015/09/01/javascript-summary/">JavaScript 总结</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-oop-function-expression-and-async/">JavaScript 面向对象程序设计、函数表达式和异步编程</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-reference-type/">JavaScript 引用类型</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-grammar/">JavaScript 基本语法</a>
          </li>
        
          <li>
            <a href="/2015/08/10/java-web/">Java Web 笔记</a>
          </li>
        
      </ul>
    </div>
  </div>


  
    
<div class="widget-wrap">
  <h3 class="widget-title">Recent Comments</h3>
  <ul class="widget ds-recent-comments" data-num-items="5" data-show-avatars="0" data-show-title="1" data-show-time="1"></ul>
</div>
<!-- 需要多说的公用代码 -->


  

</aside>

        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2015 howiefh<br>
      Powered by <a href="http://zespia.tw/hexo/" target="_blank">Hexo</a> and Theme by <a href="https://github.com/howiefh/hexo-theme-landscape-f" target="_blank" title="Landscape-F">Landscape-F</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<!-- 多说公共JS代码 start (一个网页只需插入一次) -->

<script type="text/javascript">
  var duoshuoQuery = {short_name:"howiefh"};
  (function() {
	var ds = document.createElement('script');
	ds.type = 'text/javascript';ds.async = true;
	ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
	ds.charset = 'UTF-8';
	(document.getElementsByTagName('head')[0] 
		|| document.getElementsByTagName('body')[0]).appendChild(ds);
  })();
</script> 

<!-- 多说公共JS代码 end -->

<!-- 百度分享 start -->

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":["mshare","douban","bdysc","sqq","qq","hi","baidu","huaban","youdao","sdo","mail","xg","diandian","fx","copy","print"],"bdPic":"","bdStyle":"1","bdSize":"16"},"share":{},"image":{"viewList":["qzone","tsina","tqq","renren","weixin"],"viewText":"分享到：","viewSize":"16"}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

<!-- 百度分享 end -->

<!--
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="/js/jquery.min.js"></script>
-->
<script src="/js/jquery.min.js" type="text/javascript"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<div class="bottom-btn">

	<a class="icon-gotop" href="javascript:void(0)" title="返回顶部"></a>
	<script src="/js/gotop.js" type="text/javascript"></script>
	<!--
	<script src="/js/gotop.js"></script>
	-->


	<a class="icon-toc-toggle" href="javascript:void(0)" title="文章目录"></a>
	<!--
	<script src="/js/toc_aside_toggle.js"></script>
	-->

</div>
<script src="/js/toc_aside_toggle.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>
